Используйте 2>&1, чтобы направить stdout/stderr только для одной команды среди многих в сценарии BASH

Ваша sedкоманда (с правильным цитированием):

sed 's/str1/str2/g'

Это изменит все вхождения str1на str2. Список файлов, содержащих str1, можно получить из grep -l 'str1':

.

find. -type f \( -name '*.txt' -o -name '*.git' \) \
    -exec grep -l 'str1' {} \; \
    -exec sed -i 's/str1/str2/g' {} + >changelist.txt

Здесь grep -lпредоставит список имен путей, которые будут перенаправлены в changelist.txt. Он также будет действовать как фильтр для sed, так что sedбудет запускаться только для файлов, содержащих шаблон.Затем sed -iвнесет изменения в файлы (и будет молчать ).

В качестве альтернативы пусть findнапечатает пути к файлам, которые содержат строку:

find. -type f \( -name '*.txt' -o -name '*.git' \) \
    -exec grep -q 'str1' {} \; \
    -print \
    -exec sed -i 's/str1/str2/g' {} + >changelist.txt

Похожие:

0
30.12.2019, 23:02
1 ответ

Во-первых, я предполагаю, что вы хотите, чтобы вывод grep направлялся в stderr? 2>&1 перенаправляет stderr на stdout. Вероятно, вам нужен grep 1>&2.

Во-вторых, перенаправление будет применяться только к этой единственной команде. Он не сохраняется, поэтому запуск и остановка перенаправления не проблема.

В-третьих, я не получаю :"успех" (systemd завершается нормально ). Все, что вы проверяете, это то, что вывод df -h упоминает /mnt/Backups. Что-то другое может нарушить процесс.

В-четвертых, состояние процессов в конвейерах иногда бывает неожиданным. Статус каждого процесса записывается в массив PIPESTATUS. Состояние газопровода в целом сложное. В частности, конвейер с перенаправлением может выполняться в подоболочке (, поэтому основная оболочка сохраняет свои потоки без изменений ). В таком случае я готов поверить, что ваш УСПЕХ связан со статусом выхода самой подоболочки, а не с последней командой в конвейере.

Я не уверен в этом, потому что не доверяю ему настолько, чтобы использовать его сам. Я бы хотел проверить текст, а не статус, например:(непроверенный):

MOUNT="$( df -h | grep --color=never /mnt/Backups )"
echo 1>&2 "Mount test gets ${MOUNT:-Nothing}"

if [[ "${MOUNT}" = "/mnt/Backups" ]]; then...

Этот материал очень трудно диагностировать. Я учусь использовать RC=$?для сохранения статуса команды, echo $?для отображения статуса команды, declare -p PIPESTATUSдля отображения массива статусов и RP="$( declare -p PIPESTATUS )"для сохранения массива статусов.

Проблема в том, что все четыре из этих (, включая присвоения переменной ), также являются командами и приводят к сбросу статуса на ноль. Таким образом, вы никогда не сможете увидеть свой начальный статус команды более чем по одному маршруту. Статус эфемерен, данные навсегда.

Мой лучший механизм — заставить grep подсчитывать совпадения с grep -cи сохранять возвращенное количество в переменной. Вам не нужно отбрасывать имя файла, потому что если grep читает стандартный ввод, он не выводит имя.

В качестве уточнения для больших файлов используйте grep -l.Это завершается, когда он видит, что первое совпадение(grep -cдолжно продолжать считать до конца ). grep -lвыводит имя файла, содержащего совпадение, поэтому тест выполняется для ""или "(standard input)".

1
28.01.2020, 02:38

Теги

Похожие вопросы