web-dev-qa-db-ja.com

考えられるすべてのサブディレクトリでbashコマンドを実行するにはどうすればよいですか?

私のメインディレクトリが/home/testだとしましょう

その下にはたくさんのサブディレクトリがあり、サブディレクトリの下にはまだたくさんのサブディレクトリがあります。

例:

/home/test
/home/test/subdir1
/home/test/subdir1/subdir2
/home/test/subdir1/subdir2/subdir3
/home/test/subdir1/subdir2/subdir4
/home/test/subdir1/subdir2/subdir4/subdir5

等々 ...

各ディレクトリを取得し、pwdコマンドを実行するだけの簡単なスクリプトが必要です。

7
youweek1

Parallelを使用したソリューション

GNU Parallelを使用すると、コンパクトで高速なソリューションを実現できます。

find . -type d -print0 | parallel -0 cd {}'&&' <command-name>

これは、スペースと改行を含むディレクトリ名の場合でも、まったく問題なく機能します。ここでparallelが行うことは、すべてのディレクトリであるfindから出力を取得し、それを{}を使用してcdにフィードすることです。次に、ディレクトリの変更が成功すると、このディレクトリの下で別のコマンドが実行されます。

Whileループを使用した通常のソリューション

find "$PWD" -type d | while read -r line; do cd "$line" && <command-name>; done;

$PWDがここで使用されていることに注意してください。これは、その変数に、コマンドが実行されている現在のディレクトリの絶対パスが含まれているためです。絶対パスを使用しない場合、cdはwhileループでエラーをスローする可能性があります。

これはより簡単な解決策です。ディレクトリ名に改行のような奇妙な文字が含まれている場合を除いて、ほとんどの場合機能します(コメントを参照)。

7
shivams

findコマンドは強力ですが、それを使用するのは少し難しいです。
必要なことを実行できると確信しています。以下のこのコマンドは、「ほぼ」あなたが求めているものです。

find . -type d -execdir pwd \;

ただし、これは最も深いディレクトリレベルではコマンドを実行しません。他のディレクトリが見つかったディレクトリで実行されます。

したがって、subdir4が含まれているため、subdir5で実行されます。しかし、subdir5にはありません-おそらくご想像のとおりです。

よく知られている-execdirではなく、-execオプションを使用することが重要です(man findを参照)。

-execオプションは、開始ディレクトリでコマンドを実行しますが、他にも欠点があります。

    -exec command ;
           Execute command; true if 0 status  is  returned.   All  following
           arguments  to find are taken to be arguments to the command until
           an argument consisting of ';' is encountered.  The string '{}' is
           replaced  by  the current file name being processed everywhere it
           occurs in the arguments to the command,  not  just  in  arguments
           where  it  is  alone, as in some versions of find.  Both of these
           constructions might need to be escaped (with a \ ) or quoted  to
           protect  them from expansion by the Shell.  See the EXAMPLES sec‐
           tion for examples of the use of the -exec option.  The  specified
           command  is  run once for each matched file.  The command is exe‐
           cuted in the starting directory.   There are unavoidable security
           problems  surrounding use of the -exec action; you should use the
          -execdir option instead.

しかし、オプション-execdirはまさにあなたが求めるものです:

   -execdir command ;
   -execdir command {} +
           Like  -exec,  but the specified command is run from the subdirec‐
           tory 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.  As with the -exec
           action, the '+' form of -execdir will build  a  command  line  to
           process  more  than one matched file, but any given invocation of
           command will only list files that exist in the same subdirectory.
           If  you use this option, you must ensure that your $PATH environ‐
           ment variable does not reference '.'; otherwise, an attacker  can
           run any commands they like by leaving an appropriately-named file
           in a directory in which you will run -execdir.  The same  applies
           to having entries in $PATH which are empty or which are not abso‐
           lute directory names.
5
Volker Siegel

他の答えの1つはこれに近づきました:

見つける。 -type d -exec sh -c'cd "$ 0" && cmd'{} \;

cdが成功した場合にのみコマンドを実行します)。ダミーの引数を挿入することをお勧めする人もいるので、見つかったディレクトリ({})スライドして$1

見つける。 -type d -exec sh -c'cd "$ 1" && cmd'foo {} ";"

もちろん、ここではfooの代わりに任意の文字列を使用できます。一般的な選択肢には---、およびsh。この文字列は、エラーメッセージ(存在する場合)で使用されます。例:

foo:行0:cd: 制限付きディレクトリ: アクセス拒否

したがって、shは良い選択のようです。 \;および";"は完全に同等です。それは単なるスタイルの好みです。

上記のコマンドは、ディレクトリごとに1回シェルを実行します。これには、パフォーマンスが低下する可能性があります(特に、実行するコマンドが比較的軽量の場合)。代替案が含まれます

見つける。 -type d -exec sh -c'for d; do(cd "$ d" && cmd);完了 'sh {} +

これはシェルを1回実行しますが、ディレクトリごとに1回フォークし、

見つける。 -type d -exec sh -c'save_d = $ PWD; dの場合; cd "$ d" &&を実行します cmd; cd "$ save_d";完了 'sh {} +

サブシェルを生成しません。あなたの質問が示唆するように、あなたが絶対的な道を探しているなら、あなたは上記を組み合わせてすることができます

dの/ home/test -type d -exec sh -c 'を検索します。 cd "$ d" &&を実行します cmd;完了 'sh {} +

サブシェルを生成せず、開始点を保存する必要もありません。

追加のpwdコマンドを実行する必要はなく、次のコマンドを実行できます。

find test/ -type d

ディレクトリをtest/に置き換えることができます

0
PersianGulf

あなたはこのようなものを使うことができます

find /home/test/ -type d -exec bash -c '<Command to be executed>' \; 

例:

以下のコマンドは、pwdコマンドの実行と同様に、dirnameを表示します。

find /home/test/ -type d -exec bash -c 'echo $0' \;
0
rahul