以下のwhileループを使用してファイルを読み込みます。
while read file
do
FileFound="`find $DataDir -name $file -print 2>/dev/null`"
if [ -n "$FileFound" ]; then
echo $FileFound >> ${runDir}/st_$Region
else
echo $file >> ${APP_HOME}/${Region}_filesnotfound_$date.txt
fi
done<${Region}_${date}.txt
whileループはファイル名を読み取り、datadirでそれらを比較して一致するものがあるかどうかを確認します。利用可能な場合は、フルパスをファイルに入れます。利用できない場合は、別のファイルに保存されます。ただし、このスクリプトは8000レコードを読み取るのに2日かかります。最適化する方法はありますか?
答え1
最新のLinuxデスクトップを使用している場合は、次のファイルインデックス作成ツールがあります。mlocate
バックグラウンドでファイルがすでにインストールされており、インデックス化されています。その場合は、次のものを使用できます。
while read file
do
locate "$file" >> "${runDir}/st_$Region" || echo "$file" >> "${APP_HOME}/${Region}_filesnotfound_$date.txt"
done<"${Region}_${date}.txt"
探しているファイルが頻繁に更新される場合は、まずデータベース更新を手動で強制することができます。updatedb
またはあなたのバージョンに合うものは何でも可能ですlocate
。
答え2
xargs
+へfind
xargs
1つの解決策は、非常に長いコマンドを使用してfind
何千ものファイルを一度に検索することです。
sed -e 's/^/-o -name /' "${Region}_${date}.txt" \
| xargs find "$DataDir" -false \
> "${runDir}/st_$Region"
最初のコマンドは、各ファイル名をsed
コマンドに追加される式に変換します。次に、ビルドされたコマンドを実行します。結果はファイルに直接保存されます。-o -name filename
xargs
find
xargs
find
st_$Region
美しい。しかし、${Region}_filesnotfound_$date.txt
見つからないファイルのリストをどのように作成しますか?見つかったファイルのリストと元のリスト全体を交差させるだけです。
comm -3 \
<(sort -u "${Region}_${date}.txt") \
<(xargs -L1 basename < "${runDir}/st_$Region" | sort -u) \
> "${Region}_filesnotfound_$date.txt"
comm -3
2つのファイル間の共通行を抑制します。これは実際に偽のファイルです。 2番目のファイルは、basename
見つかった各ファイルにコマンドを適用した結果です。両方のファイルがソートされました。
find
+へgrep
別の解決策は、(オプションgrep
でfind
)ファイルに保存されている一連のパターンを検索する可能性を提供することですgrep
。-f
ファイルには一連のファイル名があります。これをパターンリストにして、次に供給してみましょうgrep
。
find "$DataDir" \
| grep -f <(sed 's|.*|/&$|' "${Region}_${date}.txt") \
> "${runDir}/st_$Region"
このsed
コマンドは必須です。検索するファイル名をパスの末尾に固定します。
欠落しているファイルのリストは、他のソリューションと同じ方法で構築されます。
この回避策の問題は、ファイル名にgrep
:.
、などとして解釈できる文字を含めることができることです*
。[
私たちはこれを使ってそれらを脱出しなければなりませんsed
(私はこれを読者に練習として残します)。これが最初のソリューションがIMHOを好む理由です。
最後に、ここではいくつかの注意bash
(例:手続き型置換<(...)
)を使用しています。私のソリューションがPOSIXと互換性があるとは思わないでください。
答え3
このスクリプトは、特定のファイルが1回発生した場合にのみ機能します。したがって、異なるディレクトリに同じ名前の2つのファイルがある場合は、1つだけが報告されます。まだテストされていません。
declare -a arr
tmp1=$$tmp1
while read file
do
base=$(basename "$file")
echo "$base" >> "$tmp1"
arr["$base"]="$file"
done <(find "$DataDir")
cat "$tmp1" | sort | uniq > "$tmp1"
tmp2=$$tmp2
cat "${Region}_${date}.txt" | sort | uniq > "$tmp2"
for file in "$(join <(cat "$tmp1") <(cat "$tmp2"))"
do
echo "${arr["$file"]}" >> ${runDir}/st_$Region
done
for file in "$(cat "$tmp1" "$tmp2" | sort | uniq -u)"
do
echo "$file" >> ${APP_HOME}/${Region}_filesnotfound_$date.txt
done
rm "$tmp1"
rm "$tmp2"
答え4
このスクリプトの遅い部分は、find
ファイル全体$DataDir
で一致するものを検索することです。このコンポーネントの大部分をループの外に移動すると、時間を節約できます。
ftmp=$(mktemp -t)
find "$DataDir" >"$ftmp" 2>/dev/null
while IFS= read -r file
do
if grep -Fx -q "$file" "$ftmp" # No RE patterns. Match full line
then
echo "$file" >>"$runDir/st_$Region"
else
echo "$file" >>"${APP_HOME}/${Region}_filesnotfound_$date.txt"
fi
done <"${Region}_${date}.txt"
rm -f "$ftmp"
ファイルのリストが${Region}_${date}.txt
非常に大きい場合は、ファイル全体を渡し、リスト全体と一致grep
セットcomm
内の一致しない項目を識別して追加で保存できます。ここでの欠点は、comm
リストをソートする必要があるため、出力結果のリストもソートされることです。
fdata=$(mktemp -t)
fmatch=$(mktemp -t)
find "$DataDir" >"$fdata" 2>/dev/null
# No RE patterns. Match full line
grep -Fx -f "${Region}_${date}.txt" "$fdata" |
tee -a "$runDir/st_$Region" |
sort >"$fmatch"
# Pick out the filenames that didn't match
sort "${Region}_${date}.txt" |
comm -23 - "$fmatch" >>"${APP_HOME}/${Region}_filesnotfound_$date.txt"
rm -f "$fdata" "$fmatch"