すべてのディレクトリにcdし、そのディレクトリ内のファイルに対してコマンドを実行し、前の現在のディレクトリに戻る


41

多くの単一レベルのサブディレクトリを持つ特定のディレクトリで実行されるスクリプトを記述しようとしています。スクリプトは各サブディレクトリにcdし、ディレクトリ内のファイルに対してコマンドを実行し、cdアウトして次のディレクトリに進みます。これを行う最良の方法は何ですか?


1
与えられた情報の現在のレベルを考えると、私はに関連性がありませんyoutube-dl
HalosGhost

回答:


83
for d in ./*/ ; do (cd "$d" && somecommand); done

12
そのため、回答者はあらゆる種類の説明を省略しているため、説明を試みます。変数内のfor d in ./*/すべてのアイテム./*/(この場合はファイル/フォルダーのリスト)を格納するループを開始します$ddo (cd "$d" && somecommand);ループの本体を開始します。本体内で、サブシェルを開始し、コマンドcdsomecommandコマンドを実行します。これは子シェルであるため、親シェル(このコマンドを実行しているシェル)はそのCWDおよびその他の環境変数を保持します。done単にループ本体を閉じます。
Qix 14

この方法は、ディレクトリのサブディレクトリに対してfor d in ./*/ ; do (cd "$d" && ls); done機能します: は機能しません。しかし、for d in ./*/ ; do (cd "$d" && for d in ./*/ ; do (cd "$d" && ls); done ); done動作します。-この例では、lsをコマンドとして使用しています。
マイケルディミット

-bash: cd: ./*/: No such file or directory
S.タリクチェチン

15

最善の方法は、まったく使用cdしないことです。

find some/dir -type f -execdir somecommand {} \;

execdirはのようなものexecですが、作業ディレクトリは異なります:

   -execdir command {} [;|+]
          Like   -exec,   but  the  specified  command  is  run  from  the
          subdirectory containing the matched file, which is not  normally
          the  directory  in  which  you  started  find.  This a much more
          secure  method  for  invoking  commands,  as  it   avoids   race
          conditions  during resolution of the paths to the matched files.

POSIXではありません。


これはエイリアスで機能しますか?特定のファイルをダウンロードする必要がありますが、find * /。link -type f -execdir md $(cat .link){} \;と入力しても認識されません。
何かジョーンズ14

@SomethingJonesいいえ、findこれらのコマンドを実行するので、エイリアスを認識しません。ディレクトリmdとは何.linkですか?
ムル14

.linkは、ダウンロードする必要があるURLを含むテキストファイルです。mdは、多数のフラグが設定されたwgetのエイリアスです。エイリアスを認識させる方法はありますか?
何かジョーンズ14

あなたの特定のユースケースについては@SomethingJonesは、中bashfind . -type f -iname '*.link' -execdir ${BASH_ALIASES[md]} -i {} \;あなたは何をする必要はありませんcatwgetていた、-iファイルからURLを読み込むためのフラグを。また、これは元の質問とは多少異なります(名前が付けられたファイルのみに関心.linkがあり、存在する可能性のある他のファイルには関心がないようです)。
ムル14

zshでそれを行う方法を知っていますか?あなたが私に与えたものを試してみましたが、「Bad substitution」エラーが表示されています。また、.linkファイルのコンテンツをどのように抽出できますか?私はこの場合それを必要としないことを知っていますが、私はすぐにそうなると思います。
何かジョーンズ14

2
cd -P .
for dir in ./*/
do cd -P "$dir" ||continue
   printf %s\\n "$PWD" >&2
   command && cd "$OLDPWD" || 
! break; done || ! cd - >&2

上記のコマンドは、任意のサブシェルを行う必要はありません-それだけの交流により、現在のシェル内でその進捗状況を追跡$OLDPWDして$PWDcd -シェルがディレクトリを変更するとき、基本的にこれらの2つの変数の値を交換するとき。また、stderrで機能する各ディレクトリの名前も出力します。

私はそれをもう一度見て、エラー処理でより良い仕事をすることができると決めました。これは、その中にそれができないディレクトリをスキップしますcd-とcdstderrに理由に関するメッセージを出力します-そしてそれは意志breakあなたの場合/ゼロ以外の終了コードW command正常に実行しない場合、または実行中の場合はcommand何とか自分の元のディレクトリに戻るにはその能力に影響を与えます- $OLDPWD。その場合、cd -最後の処理も行い、結果の現在の作業ディレクトリ名をstderrに書き込みます。


1
for D in ./*; do
    if [ -d "$D" ]; then
        cd "$D"
        run_something
        cd ..
    fi
done
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.