コンテンツ/tmp/fefile
amx/eng/prf.amx
amx/eng/det.amx
bmb/menu.bmb
bmx/eng/menu.bmx
dll/tlnt.dll
dlx/eng/dlx
for file in `cat /tmp/fefile`
do
if [ -f $file ]
then
echo "File '${file}' found in $(pwd) path."
echo " Now i need to check if the that file modified in last 10 mins with the below find command "
find . -mmin -10 -type f -name ${file} -regextype posix-egrep -regex ".*/(dir1|dir1|dir3|dir4)/.+" -printf "%P\n" > /tmp/base
echo "The files that are modified recently are below"
File=(cat /tmp/base)
echo " now i am verifying that $file is matched with $File "
if[ $file == $File ]
then
echo " tmp file matched with base file."
else
echo " file doesn't match"
fi # Originally missing
else
echo "File '{file} not found."
fi
done
findコマンドで上記のスクリプトを変更してファイル名を読み、過去10分間変更されたことを確認します。
ファイルが変更されたら、2つのファイルが一致していることを確認してください。
答え1
内部に探す使用するコマンド正規表現。この正規表現は、リストされたファイル名を調べます。フェイペイファイルがありますが、この正規表現に一致するものはありません。注:ファイル内ではなくファイル名自体を確認してください。。
find . -mmin -10 -type f -name ${file} -regextype posix-egrep -regex ".*/(dir1|dir1|dir3|dir4)/.+" -printf "%P\n" > /tmp/base
それらのどれもありません:
anything in any amount
追加するdir1
またはdir1
(再び?!おそらくdir2)またはdir3
またはdir4
プラスanything in any amount but at least one
もう一つの問題は正規表現そのものです。
".*/(dir1|dir1|dir3|dir4)/.+"
おそらく次のようになります。
".*\/(dir1|dir2|dir3|dir4)\/.+"
/
次のようにエスケープを使用する必要があります\
。\/
返品:
File=(cat /tmp/base)
しなければならない:
File=$(cat /tmp/base)
または
File=`cat /tmp/base`
もう一つのポイントは行末ですfind
。
(...) -printf "%P\n" > /tmp/base
>を>>に変更することをお勧めします。
(...) -printf "%P\n" >> /tmp/base
それ以外の場合は、1つを除いて見つかったすべてのファイルを上書きします。
答え2
スクリプトスニペットの主な問題は、ループ内でfindを複数回実行することです(の各ファイル名に対して1回/tmp/fefile
)。
これは非常に遅く非効率的ですfind
。「高価」他の選択肢がない限り、ループで繰り返し実行する必要がある作業(すべてのツールを使用してディレクトリツリーを繰り返すのは時間とディスクI / Oの面で高価です)よりも優れた選択肢がほとんどあります。
一度だけ実行して出力を処理することをお勧めしますfind
(たとえば、grep、awk、sedなどを使用して)。
次のことをさらに試してください。
find ./dir[1234]/ -type f -mmin -10 -printf '%P\n' | grep -F -f /tmp/fefile
これにより、a)過去10分間修正され、b)に関連するdir1..dir4のすべてのファイルのリストが出力されます/tmp/fefile
。
ちなみに、ここでは一時/tmp/base
ファイルは必要ありません。 (しかし、一時ファイル名をスクリプトとしてハードコーディングしたり、代わりmktemp
に使用したり、同様のものを使用したりするのは一般的に悪い考えです。ハードコーディングしないでください/tmp/fefile
。この実行方法を知っておく必要があります。)
必要なものを得るには、少し調整やfind
オプションgrep
が必要な場合があります。必要な作業を把握するためにスクリプトの一部を確認するのに数分かかりましたが、それでも100%はわかりません。私はあなたが find 単独で、または find と grep (または sed、awk、perl などの他の一般的なツール) を使ってはるかに速く行うことができる非常に非効率的なタスクを実行するために約 20 行のシェル コードを使用します。あることを知っています。
注:ファイル名に改行文字が含まれていると正しく機能しません。\0
GNU grepのオプションとともに、フォーマット文字列にnotを使用できます。\n
-printf
-z
find ./dir[1234]/ -type f -mmin -10 -printf '%P\0' | grep -z -F -f /tmp/fefile
(ターミナルで出力を表示するには、出力をtr '\0' '\n'
. 、安全ではありません)
そして、ファイル名を扱う際の最良かつ安全な方法の1つは、ファイル名を配列に保存することです。たとえば、bash組み込みmapfile
(AKA readarray
)を使用します。プロセスの交換一致するすべてのファイル名で配列を入力します。
declare -a found
mapfile -d '' -t found < <(find ./dir[1234]/ -type f -mmin -10 -printf '%P\0' |
grep -z -F -f /tmp/fefile)
$found
一致するすべてのファイル名を含む配列です。配列ビューを使用するdeclare -p found
(デバッグ目的、配列に含める必要があると思うものが配列に含まれていることを確認するのに最も便利です)、コマンドの引数として使用するか、ループで使用できます。たとえば、次のようになります。
for f in "${found[@]}"; do
echo "$f"
done
"$f"
ループで何ができるのか、変数と配列にはNULを除くすべての文字を含めることができるので、二重引用符を使用する必要があります。
これはコマンド${file}
で。代わりに使用していることを思い出させます。これは非常に一般的な間違いです。変数の周りの中かっこは次のとおりです。find
"$file"
いいえ引用された代替。
パラメータ置換(ヘッダの実行man bash
と検索)に使用されます。Parameter Expansion
文字列に変数名を挿入するときに変数名を明確にします。(たとえば、変数を呼び出し$foo
て有効な変数名の文字の横にある文字列として印刷する必要がある場合は、echo "$food"
$ food値を印刷し、echo "${foo}d"
$ foo値を印刷してからリテラルd
文字を表示します。)。
バラより$VAR対${VAR}と引用。
また、見ることができますスペースやその他の特殊文字が原因でシェルスクリプトが停止するのはなぜですか?、いつ二重引用符が必要ですか?そしてbash / POSIXシェルで変数を引用することを忘れてしまうセキュリティリスク
最後に、この質問はfind
出力に関するものであり、検索に関する質問がいくつかありましたので、次を参照してください。検索結果を繰り返すのはなぜ悪い習慣ですか?。そしてリンクされた関連質問を必ず読んでください。
答え3
最後の 10 分間に最後に変更され、最後のパス コンポーネントが 1 行を構成する文字列であり、そのパスに , , 、 リストのディレクトリ コンポーネントが 1 つ以上含まれている一般的なファイルを探すことが/tmp/fefile
焦点である場合は、次のようにします。できません。と一致し、完全に完了する必要があります。dir1
dir2
dir3
dir4
-name
-path
-path
(元はBSDから来たが今は標準)一部の実装では-wholename
(と同じ-path
)、、がフルパスと-ipath
一致します。-regex
-iregex
だからいくつかのオプションは
各行に述語を使用するコマンドラインを生成します
find
。-path
/tmp/fefile
LC_ALL=C find . '(' -path '*/dir1/*' -o \ -path '*/dir2/*' -o \ -path '*/dir3/*' -o \ -path '*/dir4/*' \ ')' '(' \ -path '*/amx/eng/prf.amx' -o \ -path '*/amx/eng/det.amx' -o \ ... \ ')' -type f -mmin -10
Bashを使用すると、次のことができます。
readarray -t args < <( </tmp/fefile LC_ALL=C sed ' 1!i\ -o i\ -path s|[*/?\\]|\\&|g; # escape glob operators s|.*|*/&|') LC_ALL=C find . '(' -path '*/dir1/*' -o \ -path '*/dir2/*' -o \ -path '*/dir3/*' -o \ -path '*/dir4/*' \ ')' '(' "${args[@]}" ')'
(または
*/dir[1234]/*
これがパターンに簡単に分解できないいくつかの物理ディレクトリ名のプレースホルダであるとします。)後処理コマンドと一致するパスを残します。@casに見られるように
あるいは、
find
ここで実装したのが述語をfind
サポートするGNUであるようであるため、-regex
正規表現を動的に構成します。regex=".*/($( </tmp/fefile LC_ALL=C sed -e 's/[][$^*()+{}\\|.?]/\\&/g' | paste -sd '|' -))\$" LC_ALL=C find . -regextype posix-extended \ -regex '.*/(dir1|dir2|dir3|dir4)/.*' \ -regex "$regex" \ -type f -mmin -10
(
/tmp/fefile
空ではないと仮定)。
-exec
これらのファイルに対してコマンドを実行する必要がある場合は、いくつかの述語を追加するか、先行を削除して、-print0
NUL区切りリストを処理できる他のコマンドにNUL区切りリストを渡します(パスから任意のファイルリストを渡す安全な方法)。 。-printf '%P\0'
./