Использование grep и sed для поиска и замены строки
я использую следующее для рекурсивного поиска в каталоге определенной строки и замены ее другой:
grep -rl oldstr path | xargs sed -i 's/oldstr/newstr/g'
это работает хорошо. Единственная проблема заключается в том, что если строка не существует, то sed
не удается, потому что он не получает никаких аргументов. Это проблема для меня, так как я запускаю это автоматически с ANT и сборка не выполняется с sed
не удается.
есть ли способ сделать его отказоустойчивым в случае, если строка не найдена?
Я заинтересованы в одной линии простое решение я могу использовать (не обязательно с grep
или sed
но с общими командами unix, как эти).
7 ответов:
можно использовать
find
и-exec
непосредственно вsed
вместо того, чтобы сначала найтиoldstr
Сgrep
. Это может быть немного менее эффективно, но это может быть не важно. Сюда, вsed
замена выполняется над всеми файлами, перечисленнымиfind
, а еслиoldstr
нет, очевидно, не будет работать на нем.find /path -type f -exec sed -i 's/oldstr/newstr/g' {} \;
ваше решение в порядке. только попробуйте это таким образом:
files=$(grep -rl oldstr path) && echo $files | xargs sed....
поэтому выполнить
xargs
только когда grep return0
, например, при обнаружении строки в некоторых файлах.
стандартный
xargs
не имеет хорошего способа сделать это; вам лучше использоватьfind -exec
как кто-то предложил, или обернутьsed
в скрипте, который ничего не делает, если нет аргументов. GNUxargs
имеет--no-run-if-empty
вариант, и BSD / OS Xxargs
имеет-L
вариант, который выглядит так, как будто он должен сделать что-то подобное.
Я взял идею Влада и немного изменил ее. Вместо
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 подключения к серверу (возможно, есть способ сделать все это в одной строке), он также эффективно выполняет эту работу
Я думаю, что без использования
-exec
вы можете просто предоставить/dev/null
как минимум один аргумент в случае, если ничего не нашел:grep -rl oldstr path | xargs sed -i 's/oldstr/newstr/g' /dev/null
мой вариант использования был я хотел заменить
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'
надеюсь, что помогла.
если вы должны заменить фиксированную строку или какой-либо шаблон, я также хотел бы добавить конструкцию замены переменной замены строки шаблона bash builtin. Вместо того, чтобы описывать его Сам, я цитирую раздел из руководства bash:
${parameter/pattern/string}
шаблон расширяется, чтобы создать шаблон так же, как в pathname расширение. параметр расширяется и самый длинный матч pattern против его значения заменяется на строка. Если pattern начинается с
/
все матчи pattern заменяются строкой. Обычно заменяется только первый матч. Если pattern начинается с#
, он должен соответствовать в начале расширенного значения параметр. Если pattern начинается с%
, он должен соответствовать в конце расширенного значения параметр. Если строка равно null, соответствует из pattern удаляются и/
после pattern может быть опущен. Если параметр и@
или*
, операция замены применяется к каждому позиционному параметру по очереди, а расширение это результирующий список. Если параметр - это переменная массива, подписанная на@
или*
, операция подстановки применяется к каждый элемент массива, в свою очередь, и расширение это итоговый список.