Использование 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 может быть опущен. Если параметр и@или*, операция замены применяется к каждому позиционному параметру по очереди, а расширение это результирующий список. Если параметр - это переменная массива, подписанная на@или*, операция подстановки применяется к каждый элемент массива, в свою очередь, и расширение это итоговый список.