Использование grep и sed для поиска и замены строки - PullRequest
66 голосов
/ 30 мая 2011

Я использую следующее для рекурсивного поиска в каталоге определенной строки и замены ее на другую:

grep -rl oldstr path | xargs sed -i 's/oldstr/newstr/g'

Это работает нормально.Единственная проблема заключается в том, что если строка не существует, то sed завершается ошибкой, поскольку она не получает никаких аргументов.Это проблема для меня, так как я запускаю это автоматически с ANT, и сборка завершается неудачно, так как sed не удается.

Есть ли способ сделать его безошибочным в случае, если строка не найдена?

Меня интересует простое решение в одну строку, которое я могу использовать (не обязательно с grep или sed, но с такими общими командами unix, как эти).

Ответы [ 7 ]

69 голосов
/ 30 мая 2011

Вы можете использовать find и -exec непосредственно в sed вместо того, чтобы сначала найти oldstr с grep. Это может быть немного менее эффективно, но это может быть не важно. Таким образом, замена sed выполняется для всех файлов, перечисленных в find, но если oldstr нет, она, очевидно, не будет работать с ней.

find /path -type f -exec sed -i 's/oldstr/newstr/g' {} \;
9 голосов
/ 31 мая 2011

Ваше решение в порядке. только попробуйте это так:

files=$(grep -rl oldstr path) && echo $files | xargs sed....

, поэтому выполните xargs только тогда, когда grep вернет 0, например когда нашел строку в некоторых файлах.

7 голосов
/ 30 мая 2011

Я взял идею Влада и немного ее изменил.Вместо

grep -rl oldstr path | xargs sed -i 's/oldstr/newstr/g' /dev/null

Что дает

sed: couldn't edit /dev/null: not a regular file

Я делаю 3 разных подключения к удаленному серверу

touch deleteme
grep -rl oldstr path | xargs sed -i 's/oldstr/newstr/g' ./deleteme
rm deleteme

Хотя это менее элегантно и требуетЕще 2 подключения к серверу (возможно, есть способ сделать все это в одной строке), это также эффективно выполняет свою работу

7 голосов
/ 30 мая 2011

Стандарт xargs не имеет хорошего способа сделать это;вам лучше использовать find -exec, как кто-то другой предложил, или обернуть sed в сценарий, который ничего не делает, если нет аргументов.GNU xargs имеет опцию --no-run-if-empty, а BSD / OS X xargs имеет опцию -L, которая выглядит так, как будто она должна делать что-то подобное.

4 голосов
/ 30 мая 2011

Я думаю, что без использования -exec вы можете просто указать /dev/null как минимум один аргумент, если ничего не найдено:

grep -rl oldstr path | xargs sed -i 's/oldstr/newstr/g' /dev/null
1 голос
/ 22 мая 2013

Мой вариант использования был, я хотел заменить foo:/Drive_Letter с foo:/bar/baz/xyz В моем случае я смог сделать это с помощью следующего кода. Я находился в той же папке, где было много файлов.

find . -name "*.library" -print0 | xargs -0 sed -i '' -e 's/foo:\/Drive_Letter:/foo:\/bar\/baz\/xyz/g'

надеюсь, что помогло.

0 голосов
/ 30 мая 2011

Если вы хотите заменить фиксированную строку или какой-либо шаблон, я также хотел бы добавить встроенную в bash конструкцию подстановки переменных для замены строки шаблона. Вместо того, чтобы описывать это сам, я цитирую раздел из руководства по bash:

${parameter/pattern/string}

Шаблон расширяется, чтобы создать шаблон так же, как в pathname расширение. параметр раскрывается, и самое длинное совпадение pattern с его значением заменяется на string . Если шаблон начинается с /, все совпадения pattern заменяются на строку. Обычно заменяется только первый матч. Если начинается паттерн с #, оно должно совпадать в начале расширенного значения * * Параметр тысяча двадцать-один * * 1 022. Если шаблон начинается с %, он должен совпадать в конце расширенного значения параметр . Если строка равна нулю, соответствует шаблон удаляются, а / следующий шаблон может быть опущен. Если параметр равен @ или *, операция замещения будет применяется к каждому позиционному параметру по очереди, а расширение является результирующим списком. Если параметр является переменной массива, подписанной @ или *, операция замещения применяется к каждый член массива в свою очередь, и расширение является результирующий список.

...