web-dev-qa-db-ja.com

「file.txt」という名前のすべてのファイルを再帰的に検索し、sedコマンドを実行します

私のタスクの課題は、file.txtがサブフォルダーまたはサブサブフォルダーにある可能性があることです。一般的な構造は次のようになります。

   folder
     |___subfolder
             |_____file.txt
     |
     |___subfolder
             |____subfolder
                      |_______file.txt
     etc

以前のコードはサブサブフォルダーを処理せず、この部分に追加する方法がわかりません(一部のサブフォルダーには後続のフォルダーがないため)

 for dir in ./*/ ; do
        if [ -d "$dir" ]; then 
           cd $d;
           for subdir in ./*/; do
               cd $subdir && $(sed command file.txt) && cd ..;
           done
           cd ..
        fi
done

また、findを使用する1行の方法があることも学びました。

find . -name 'file.txt' | sed command file.txt

どうやらこれはfindが私のfile.txtにディレクトリを返すだけなので機能しません

5
dwuuuu

試してください:

find . -name 'file.txt' -exec sed command {} +

これにより、file.txtというサブディレクトリにある.という名前のすべてのファイルが検索され、それらのファイルに対してsed commandが実行されます。

sedでこれらのファイルを適切に変更する場合は、-iオプションを追加します。

[〜#〜] posix [〜#〜] には-exec ... +が必要になりましたが(ヒント:ヨルダン)、BSDの古いバージョンを使用している人もいますfind+をサポートしていません。それらのいずれかを持っている場合は、(ハットのヒント:unxnut)を使用します。

find . -name 'file.txt' -exec sed command {} \;

より安全な代替手段

ディレクトリ構造が急激に変更されると、-execが競合状態になる可能性があります。セキュリティを強化するには、-execdirを使用します(ヒント:unxnut)。

find . -name 'file.txt' -execdir sed command {} +

PATHに現在のディレクトリがある場合、-execdirは実行を拒否することに注意してください。

15
John1024

そのsedコマンドが何をしているかわからない場合は、入力ファイルごとに1つのsedを実行する必要があります。
これは、forループ(シェルが再帰的グロビングをサポートしている場合)のいずれかを使用して実行できます。 zshksh93yashbashtcsh and fishもループ構文は異なります)。

shopt -s globstar        # bash
#set -o globstar         # ksh93
#set -o extended-glob    # yash

for f in **/file.txt; do [ -f "$f" ] && sed 'cmd' "$f"; done

または(他の人が指摘したように)find

find . -type f -name 'file.txt' -exec sed 'cmd' {} \;

さて、不思議に思うかもしれません-なぜこれを「最適化」して、finds -exec+とともに使用するか、次のようなzsh- ismを使用しないでください。

sed 'cmd' **/file.txt(.)

確かに、これらは複数のfileオペランドを使用してsedを呼び出すため、より効率的ですが、thatが問題を解決する可能性があります。
簡単にするために、sedコマンド1qを使用して各ファイルの1行目のみを印刷しようとしていると想像してください。1 (ファイルをその場で編集せずに2、結合された出力を別のファイルにリダイレクトするため、または単にそれを検査するため)、どちらかを実行します

find . -name 'file.txt' -exec sed '1q' {} +

または

sed '1q' **/file.txt(.)

ただし、どちらも配信に失敗します。
複数のファイルオペランドが指定されている場合、指定されたファイルが指定された順序で読み込まれ、連結が編集されます
その結果、sedは各ファイルの1行目ではなく、入力の1行目のみを出力します
現在、gnu sedには-sスイッチがあります。

-s, --separate
        consider files as separate rather than as a single continuous long stream

これは時々役に立ちますが、この特定のケース(1q)では役に立ちません。


1:1qが気に入らない場合は、$dを試してください。これにより、各ファイルの最後の行が削除されます
2:gnu sed-iを意味するため、-sを使用して回避できる場合がありますが、sedコマンドの1つがqの場合は、そうではありません
3:qが終了したためと主張するかもしれませんが、sed -n '1p'を使用した場合も同じことが起こります。私はqのみを使用して強調しました2:

3
don_crissti