"find -exec"を使用して見つかったファイルのディレクトリ(現在のディレクトリではない)からコマンドを実行するには?

"find -exec"を使用して見つかったファイルのディレクトリ(現在のディレクトリではない)からコマンドを実行するには?

私があるディレクトリに、およびサブディレクトリがあるとしdir1ます。各ディレクトリにはファイルがあり、各ディレクトリの各ディレクトリで同じコマンドを実行し、そのディレクトリ内でコマンドを実行したいと思います。dir2dir3foofoo

私が「手で」実行した場合は、次のようになります。

cd dir1
(execute on foo)
cd ../dir2
(execute on foo)
cd ../dir3
(execute on foo)

このコマンドを実行する必要があります。各ディレクトリでfooバッチ予約スクリプト(不思議な場合はHTCondor用)であり、予約スクリプトによって開始された実行の出力が各サブディレクトリで終わるように各サブディレクトリで実行する必要があります。

質問」ファイルディレクトリからファイルを検索してコマンドを実行する私が知る限り、私の質問に対する答えはありません。質問に対する最初の答えは解決策に近いので、私の場合はうまくいかず、2番目の答えは使用方法を知るのに十分ではありません。

答え1

findサポートしていると仮定すると、-execdir代わりにこのオプションを使用してください。-exec

find . -type f -name 'foo' -execdir pwd \;

その後、各ディレクトリに順番に変更され、対応するfooファイルがある場合は実行されますpwd

注:このソリューションの目的を変更して、名前付きディレクトリからコマンドを実行することはできませんfoo。これを行うには、提供された各パラメータを繰り返し、各パラメータを順番に使用する-exec sh -c '...'簡単なアプローチに戻る必要があります。この例は各ディレクトリで実行されます。shcdpwd

find . -type d -name 'foodir' -exec sh -c '
    for d in "$@"; do ( cd "$d" || exit; pwd ); done
    ' _ {} +

答え2

コマンドを実行するディレクトリを正確に知っていると仮定すると、

for dir in dir1 dir2 dir3; do
    ( cd "$dir" && somecommand foo )
done

またはfooファイルを繰り返し

for foo in ./*/foo; do
  ( cd "${foo%/foo}" && somecommand foo )
done

サブシェルは、cd作業ディレクトリがスクリプトの残りの部分に影響を与えるのを防ぎます。引数${foo%/foo}置換は、ファイルのあるディレクトリの名前まで拡張されます(値からKnowsサフィックス文字列を削除することによってfoo)。/foo$foo

同じ操作を実行するには、標準を使用します(findファイルがディレクトリ構造に深くある可能性がある場合)。foo

find . -type f -name foo -exec sh -c '
    for foo do
        ( cd "${foo%/foo}" && somecommand foo )
    done' sh {} +

つまり:現在のディレクトリまたはその下のどこでも、「foo」という名前のすべての一般的なファイルを見つけ、そのパス名をこのシェルスクリプトに一括して提供します。シェルスクリプトは与えられたパス名を繰り返し、ディレクトリを各パス名のディレクトリ部分に変更し、成功したら実行する必要がありますsomecommand foo

非標準を使用するソリューションについては、-execdir次を参照してください。エマ・ルーオの答え。彼の答えは私の例に適しています。

find . -type f -name foo -execdir somecommand foo ';'

答え3

きれいではないかもしれませんが、仕事を終えると思います。

find . -name 'foo' -type f -exec sh -c 'cd $(echo {}|cut -d"/" -f2) && ./foo' \;

答え4

Win 10のWSLとGitBashでテストされました。

以前のソリューションのexecdirは、現在のディレクトリに入るのではなく、現在のディレクトリを引数として使用してコマンドが実行されるため、機能しません。
ディレクトリにCDを挿入して必要な操作を実行します。
たとえば、作業を開始する前にすべてのリポジトリを更新するために使用します。

find $HOME/workspace/ -maxdepth 1 -type d -name "repo*" -exec bash -c "cd \"{}\" && echo ____Pulling from \"{}\" && git pull" \;

編集:
PC/ノートブックを使用せずにより強力なコードが必要な場合は、外部コマンドを使用して挿入できないスクリプトを作成する必要があります。たとえば、次のようになります。

#!/bin/sh
find "$HOME/workspace/" -maxdepth 1 -type d -exec sh -c '
  for dir in "$@"
  do
    echo "____Pulling from $dir"
    cd "$dir"
    git pull
  done' sh {} +

関連情報