一致する文字列を含むファイルを含むディレクトリパスの抽出

一致する文字列を含むファイルを含むディレクトリパスの抽出

results.out ファイルを含む複数レベルのサブディレクトリが複数あります。

./dir1/results.out
./dir2/dir21/results.out
./dir3/dir31/dir311/results.out

これらのサブディレクトリを別の場所に移動する必要があるため、含まれているstring1ディレクトリパスを検索して抽出する必要があります。results.outたとえば、次のコードを使用してファイルパスを取得できます。results.outstring1

for i in $(find . -type f -name "results.out);
do
grep -l "string1" $i
done

ディレクトリパスのみを取得するには、上記のコードをどのように変更する必要がありますか?

答え1

GNUがある場合は、フォーマット指定子を使用してfindパスを印刷できます。%h

    %h     Leading directories of file's name (all but the last ele‐
           ment).  If the file name contains no slashes (since it is
           in  the  current  directory)  the %h specifier expands to
           ".".

たとえば、あなたはできます

find . -name 'results.out' -exec grep -q 'string1' {} \; -printf '%h\n'

答え2

そしてzsh

print -rl ./**/results.out(.e_'grep -q string $REPLY'_:h)

これは、.()という名前の一般的なファイルを再帰的に検索してresults.out評価した場合、各ファイルで実行されます。grep -q ...e本物hパスの先頭(最後の要素を持たないパス)のみを印刷します。


findshおよび拡張機能を使用して${parameter%/*}ヘッダーを抽出する別の方法は次のとおりです。

find . -type f -name results.out -exec grep -q string {} \; \
-exec sh -c 'printf %s\\n "${1%/*}"' bang {} \;

答え3

for i in $(find . -type f -name "results.out);
do
grep -l "string1" $i ; exitcode=${?}
if [ ${exitcode} -eq 0 ]  # string1 is found in file $i
then
   path=${i%/*}
   echo ${path}
fi
done

答え4

私が正しく理解したと仮定すると、次のことをしたいと思います。

find . -type f -name "results.out" -exec grep -l "string1" {} \; | xargs dirname

最初の部分は一致するファイル名を取得し、xargsはこれらのファイル名をdirnameプログラムに引数として渡し、パスからファイル名を「削除」します。

関連情報