すべてのサブディレクトリを再帰的に移動し、特定の拡張子を持つファイルがある場合は、そのフォルダでコマンドを一度実行します。

すべてのサブディレクトリを再帰的に移動し、特定の拡張子を持つファイルがある場合は、そのフォルダでコマンドを一度実行します。

フォルダ内のすべてのサブディレクトリを再帰的に参照する必要があります。サブディレクトリに拡張子が ".xyz"のファイルがある場合は、そのフォルダで特定のコマンドを一度実行する必要があります。

これが私が今まで持っているものです

recursive() {
  for d in *; do
    if [ -d "$d" ]; then
      (cd -- "$d" && recursive)
    fi
  dir=`pwd`   
  pattern="*.xyz"
file_count=$(find $dir -name $pattern | wc -l)
if [[ $file_count -gt 0 ]]; then
    echo "Match found. Going to execute a command"
    #execute command
fi
  done
}

(cd /target; recursive)

ところで、問題は、一致するものがあるときに「一致項目が見つかりました」というメッセージが各フォルダに複数回表示されることです。この問題を解決しながら、より簡単な方法はありますか?

ベストアンサー1

あなたは再創造していますfind

次のようにしてみてください(GNUfindutilsとGNUを使用sort)。

find /target -iname '*.xyz' -printf '%h\000' | sort -z -u | 
  xargs -0 -r -I {} sh -c "cd {} ; yourcommandhere"

「*.xyz」ファイルのあるディレクトリ名()を-printfNULバイト()で区切って印刷します。重複を削除し、各ディレクトリに移動して実行します。%h\000sortxargscdyourcommandhere

xargs を使用して実行するスクリプトを作成することもできます。例えば

find /target -iname '*.xyz' -printf '%h\000' | sort -z -u | 
  xargs -0 -r /path/to/myscript.sh

単純なmyscript.shの例:

#!/bin/sh

for d in "$@" ; do
  cd "$d"
  echo "Match found in $d. Going to execute command"
  # execute command
done

一致するディレクトリが多い場合、2番目のバージョンははるかに高速です。つまり、ディレクトリごとにシェルをフォークするのではなく、シェルを一度だけフォークしてから、各引数に対して繰り返します。


ところで、ここではどちらも実際にはprintf必要ありません。しかし、何が起こっているのかを読んで理解しやすくなります。同様に重要なのは、(printfとsortを使用して)最初に重複するエントリを削除することでbashを使用するよりもはるかに速く実行され、特定のディレクトリでコマンドを複数回実行する危険(やや小さい)を排除することです。sortxargs

ソートや xargs なしで同じ操作を実行する別の方法は次のとおりです。

find /target -iname '*.xyz' -exec bash -c \
    'typeset -A seen
     for f in "$@"; do
       d="$(dirname "$f")";
       if [[ ! -v $seen[$d] ]]; then
         echo "Match found in $d. Going to execute command"
         # Execute command
         seen["$d"]=1
       fi
     done' {} +

これはbash()の連想配列を使用して、$seen[]どのディレクトリが検索され処理されたかを追跡します。何千もの一致するファイルがある場合*.xml(bashスクリプトが複数回フォークできるように最大コマンドライン長を超えるのに十分です)、次のコマンドを実行します。可能特定のディレクトリで複数回実行します。

findオプションで実行されるスクリプトは、上記-execのxargsバージョンなどのスタンドアロンスクリプトです。

しかし、ここのすべてのバリアントは、awkやperl、shやbashスクリプトではなく、すべてのスクリプトを簡単に実行できます。

おすすめ記事