42793


**ディレクトリ内を再帰的に全置換する際、grepを使用するかfindを使用するかいつも迷うのですが**  
・下記は同じ意味ですか？

[code]

    grep -rl 置換前 . | xargs sed -i 's/置換前/置換後/g'
    
    find . -type f - | xargs sed -i 's/置換前/置換後/g'　
    
    find . -type f -exec sed -i 's/置換前/置換後/g' {} +　
    
    find . -type f -exec sed -i 's/置換前/置換後/g' {} \
    
[/code]

* * *

・基本的には、findの方がファイルタイプを指定できるので、出来ることが多い？  
・ディレクトリ名やファイル名の置換はgrepでは出来ない？


CC BY-SA 3.0
2018-03-30T02:05:42.900
42765
2018-03-30T11:45:06.297
7886
question
unix
ディレクトリ内を再帰的に全置換する時の選択肢


4つのコマンドは、それぞれ異なる動作をします。

  * `grep | xargs sed` は、同じファイルを二度走査することになる無駄があります。一度の走査で済む他3つのコマンドに比べ、ファイルサイズが大きくなると速度差が出てくるでしょう。
  * `grep | xargs sed` と `find | xargs sed` は、意図しているように動かない可能性があります。たとえばファイル名に半角スペースが含まれている場合、パイプで一旦ただの文字列に戻ってしまうので `sed` 側に正しく認識されません。これが `find` コマンドの `-exec` オプションが必要な理由です。以下は上手くいかない例です。
[code]     $ echo foo > aaa

    $ echo foo > bbb
    $ echo foo > 'ccc ddd'
    $ ls
    aaa  bbb  ccc ddd
    $ find . -type f | xargs sed -i 's/foo/bar/g'
    sed: can't read ./ccc: No such file or directory
    sed: can't read ddd: No such file or directory
    $ 
    
[/code]

また、この回答では詳説しませんが、この問題を解決するために `find`
の[区切り文字を変える方法](https://stackoverflow.com/a/864330/5989200)があります。

  * `grep | xargs sed` と `find | xargs sed` は、置換対象のファイルが存在しなかった場合の挙動が他と違います。この2つは該当するファイルが存在しなくても `sed` を実行し、入力ファイルが無いというエラーを出しますが、他の2つはこの場合 `sed` を実行しません。以下は動作例です。
[code]     $ ls

    aaa  bbb  ccc ddd
    $ find . -type f -name xxx | xargs sed -i 's/foo/bar/g'
    sed: no input files
    $ find . -type f -name xxx -exec sed -i 's/foo/bar/g' \;
    $ 
    
[/code]

  * Qiita の記事[「find の -exec optionの末尾につく \; と + の違い。」](https://qiita.com/ironsand/items/0aed2ffca295706cab69)で触れられているように、`;` と `+` では見つかったファイル名をひとつずつ渡すか、ある程度まとめて渡すかの違いがあります。`+` を使うと実行する `sed` インスタンスの数を減らすことができます。

よって、基本的には `find` コマンドの `-exec` オプションを使うのが安全だと思います。


CC BY-SA 3.0
2018-03-30T10:17:03.180
42793
2018-03-30T11:45:06.297
2018-03-30T11:45:06.297
19110
19110
42765
answer