grepはsedにパイプしてインラインを置き換えますが、sedはファイル名を印刷して行を変更したいと思います。可能ですか?

grepはsedにパイプしてインラインを置き換えますが、sedはファイル名を印刷して行を変更したいと思います。可能ですか?

私のコマンドは次のとおりです(意図的に中断されました)。

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

高レベルで:ディレクトリgrepのFOO。インライン置換()を実行し、ファイルblah名のみを-lパイプします。sedsed-i ''変更された用語のみ到着する/dev/stdout

-lとパイプを省略すると、次のようになります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/それが重要な場合sedgrepしばらくしてくださいsed

答え1

grep1つの可能性はの出力を渡すことです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

答え2

私の母国語は英語ではないので理解できないかもしれません。

ディレクトリを「grep」するには、「-r」が必要です。ファイル名のみを印刷し、最初の発生後にgrepを停止するには、「-l」を使用します。

# pattern=/home ; grep -l "$pattern" /etc/[a-z]* 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

答え3

現在のディレクトリでFOOをBARに繰り返し交換します(自動モード)。

grep -rl 'FOO' | xargs sed -i 's/FOO/BAR/'

答え4

短い冗談

grep -n FOO * -R|awk -F\: '{ print $1 }'|sort|uniq|while read file; do sed -i 's/FOO/BAR/g' $file; done

関連情報