私のタスクの課題は、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
にディレクトリを返すだけなので機能しません
試してください:
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
は実行を拒否することに注意してください。
そのsed
コマンドが何をしているかわからない場合は、入力ファイルごとに1つのsed
を実行する必要があります。
これは、for
ループ(シェルが再帰的グロビングをサポートしている場合)のいずれかを使用して実行できます。 zsh
、ksh93
、yash
、bash
(tcsh
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' {} \;
さて、不思議に思うかもしれません-なぜこれを「最適化」して、find
s -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行目のみを出力します3。
現在、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: