Intereting Posts

grep трубопроводы в sed, заменяя inline; но я хочу, чтобы sed печатал имя файла и менял строку. Является ли это возможным?

Вот моя команда (перерыв намеренно):

grep FOO "/Users/gjtorikian/blah" -l | xargs sed -i '' '/FOO/{s/FOO/BAR/g; w /dev/stdout }' 

На высоком уровне: grep для FOO в каталоге blah ; pipe только в имени файла (из-за -l ) в sed ; sed выполняет inline replace ( -i '' ) и печатает только измененный термин в /dev/stdout .

Если бы я опустил -l и pipe, я вернусь от grep :

 /Users/gjtorikian/blah/baz.cs:1:FOO /Users/gjtorikian/blah/bar.js:1:FOO 

Я хочу, чтобы sed выполнял встроенную замену, а затем показывал мне замененный файл и термин; например:

 /Users/gjtorikian/blah/baz.cs:1:BAR /Users/gjtorikian/blah/bar.js:1:BAR 

Возможно ли это? Если это имеет значение, я бы предпочел сохранить его только с grep / sed . Должен ли я сделать второй grep после sed ?

Одной из возможностей было бы передать выход grep отдельному sed фильтру.

 grep -l FOO "/Users/gjtorikian/blah/"* | { tee /dev/fd/3 | xargs sed -i -e '/FOO/{' -e 's/FOO/BAR/g' -e 'w /dev/stdout' } 3>&1 | sed 's/:FOO$/:BAR/' 

Вы можете заставить sed напечатать номер строки (с помощью команды = ), когда она найдет совпадение и сделает дальнейшую постобработку.

Вероятно, было бы лучше использовать awk.

 for x in "/Users/gjtorikian/blah/"*; do awk ' sub(/FOO/, "BAR") {found=1; print FILENAME ":" NR ":" "BAR" >"/dev/stderr"} 1 {print} END {exit(!found)} ' "$x" >"$x.tmp" && mv "$x.tmp" "$x" done 

Поскольку я не являюсь носителем английского языка, я, вероятно, этого не понял.

Чтобы «grep» создать каталог, вам нужно «-r». Использование '-l' печатает только имя файла и останавливает grepping после первого появления.

 # pattern=/home ; grep -l "$pattern" /etc/[az]* 2>/dev/null | while read line ; do echo "$line:$pattern" ; done /etc/adduser.conf:/home /etc/fstab:/home /etc/fstab~:/home /etc/libuser.conf:/home /etc/mpd.conf:/home /etc/mpd.conf~:/home /etc/mtab:/home /etc/netscsid.conf:/home /etc/passwd:/home /etc/passwd-:/home /etc/sudoers:/home /etc/sudoers.tmp~:/home и # pattern=/home ; grep -l "$pattern" /etc/[az]* 2>/dev/null | while read line ; do echo "$line:$pattern" ; done /etc/adduser.conf:/home /etc/fstab:/home /etc/fstab~:/home /etc/libuser.conf:/home /etc/mpd.conf:/home /etc/mpd.conf~:/home /etc/mtab:/home /etc/netscsid.conf:/home /etc/passwd:/home /etc/passwd-:/home /etc/sudoers:/home /etc/sudoers.tmp~:/home и # pattern=/home ; grep -l "$pattern" /etc/[az]* 2>/dev/null | while read line ; do echo "$line:$pattern" ; done /etc/adduser.conf:/home /etc/fstab:/home /etc/fstab~:/home /etc/libuser.conf:/home /etc/mpd.conf:/home /etc/mpd.conf~:/home /etc/mtab:/home /etc/netscsid.conf:/home /etc/passwd:/home /etc/passwd-:/home /etc/sudoers:/home /etc/sudoers.tmp~:/home и # pattern=/home ; grep -l "$pattern" /etc/[az]* 2>/dev/null | while read line ; do echo "$line:$pattern" ; done /etc/adduser.conf:/home /etc/fstab:/home /etc/fstab~:/home /etc/libuser.conf:/home /etc/mpd.conf:/home /etc/mpd.conf~:/home /etc/mtab:/home /etc/netscsid.conf:/home /etc/passwd:/home /etc/passwd-:/home /etc/sudoers:/home /etc/sudoers.tmp~:/home и # pattern=/home ; grep -l "$pattern" /etc/[az]* 2>/dev/null | while read line ; do echo "$line:$pattern" ; done /etc/adduser.conf:/home /etc/fstab:/home /etc/fstab~:/home /etc/libuser.conf:/home /etc/mpd.conf:/home /etc/mpd.conf~:/home /etc/mtab:/home /etc/netscsid.conf:/home /etc/passwd:/home /etc/passwd-:/home /etc/sudoers:/home /etc/sudoers.tmp~:/home и # pattern=/home ; grep -l "$pattern" /etc/[az]* 2>/dev/null | while read line ; do echo "$line:$pattern" ; done /etc/adduser.conf:/home /etc/fstab:/home /etc/fstab~:/home /etc/libuser.conf:/home /etc/mpd.conf:/home /etc/mpd.conf~:/home /etc/mtab:/home /etc/netscsid.conf:/home /etc/passwd:/home /etc/passwd-:/home /etc/sudoers:/home /etc/sudoers.tmp~:/home и # pattern=/home ; grep -l "$pattern" /etc/[az]* 2>/dev/null | while read line ; do echo "$line:$pattern" ; done /etc/adduser.conf:/home /etc/fstab:/home /etc/fstab~:/home /etc/libuser.conf:/home /etc/mpd.conf:/home /etc/mpd.conf~:/home /etc/mtab:/home /etc/netscsid.conf:/home /etc/passwd:/home /etc/passwd-:/home /etc/sudoers:/home /etc/sudoers.tmp~:/home 

Я думаю, что вы делаете проблему слишком сложной, пытаясь сделать это за один раз. Вы просто можете сделать

 grep -H -n /Users/gjtorikian/blah | sed 's/\(^.*?:[0-9]+?:\).*FOO.*/\1BAZ/' 

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

 sed -i '' 's/FOO/BAR/g' /Users/gjtorikian/blah 

Здесь не нужны grep и xarg (вы можете сделать «find … | xarg», если у вас много файлов). Если вас беспокоит дублирование, вы можете поместить две строки в скрипт или функцию и там заменить переменные.