可能なすべてのサブディレクトリでbashコマンドを実行するには?

可能なすべてのサブディレクトリで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

答え1

並列ソリューションの使用

小型で高速なソリューションにはGNU Parallelを使用できます。

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

これは、スペースと改行文字を含むディレクトリ名にも絶対に機能します。これが何をするかは、各ディレクトリparallelから出力を取得してから。その後、ディレクトリの変更が成功すると、このディレクトリで別のコマンドが実行されます。find{}

whileループを使用する一般的なソリューション

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

$PWD変数には以下が含まれているため、ここではこれが使用されます。絶対パスコマンドが実行される現在のディレクトリ。絶対パスを使用しないと、cdwhileループでエラーが発生する可能性があります。

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

答え2

この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.

答え3

他の答えの1つは次のとおりです。

探す。 -type d -exec sh -c 'cd "$0" &&ガイドライン'{}\;

cdコマンドは成功した場合にのみ実行されます。)一部の人は、見つかったディレクトリ({})が次に移動するようにダミーパラメータを挿入することを提案しました$1

探す。 -type d -exec sh -c 'cd "$1" &&ガイドライン'foo{}";"

もちろん、ここでは代わりに任意の文字列を使用できますfoo。一般的な選択には---とが含まれますsh。この文字列はエラーメッセージ(存在する場合)に使用されます。たとえば、次のようになります。

foo: 行 0: cd:制限されたディレクトリ:権限が拒否されました

だからsh良い選択のようです。  \;そして";"それは絶対に同じです。それはスタイルの好みだけです。

上記のコマンドは、各ディレクトリに対して一度シェルを実行します。これにより、わずかなパフォーマンスが低下する可能性があります(特に実行するコマンドが比較的軽い場合)。代替案は次のとおりです。

探す。 -type d -exec sh -c 'd;do(cd "$d"&&ガイドライン);完了 'sh{}+

シェルは一度実行されますが、各ディレクトリに対して1回分岐します。

探す。 -type d -exec sh -c 'save_d=$PWD;実行cd "$d" &&ガイドライン; cd "$save_d";完了 ' sh {} +

サブシェルを作成しません。あなたの質問が示すように、絶対パスを検索する場合は、上記の内容を組み合わせて実行できます。

d;execute cd "$d" && の /home/test -type d -exec sh -c ' を探します。ガイドライン;完了' sh {} +

サブシェルを作成せず、開始点を保存しません。

答え4

このようなものを使用できます

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

例:

次のコマンドは、pwdコマンドの実行と同様にディレクトリ名を表示します。

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

関連情報