私が知っている限り、awkは2つの方法で使用できます。ファイルのリストをパラメータとして渡すか、パイプラインで使用できます。ファイルリストをパラメータとして使用したので、BEGIN
andEND
ブロックはすべてのファイルに対して一度だけ実行されます。しかし、問題があります。ファイルをawkに渡すには、まずファイルの復号化が必要です。そのため、次のようにパイプラインを設定しました。
find . -name "*.gpg" -exec sh -c "gpg -d {} | awk -f process.awk" \;
これですべてのファイルが実行されBEGIN
ブロックEND
されますが、process.awk
これは私が望むものではありません。ブロックが一度だけ実行されるようにawkに渡されたファイルを復号化する方法はありますか?更新:ファイル名も必要なので、process.awk
ファイルの内容を別々にインポートする方が良いと思いました。ただし、これは見つかったすべてのファイルに対して一度だけ実行する必要があるという要件に違反します。そうですかBEGIN
?END
ベストアンサー1
ファイル名に改行文字が含まれていないとします。
while IFS= read -r fname; do
gpg -d "$fname"
done < <(find . -name '*.gpg') |
awk -f process.awk
今話していることを行い、各ファイル名をawkに渡すには、最も簡単な方法は次のとおりです(bash 4. *を使用またはreadarray
埋めるmapfile
ループを作成するとしますfnames[]
)。
readarray -t fnames < <(find . -name '*.gpg')
for fname in "${fnames[@]}"; do
gpg -d "$fname" |
awk -v fname="$fname" -v tot="${#fnames[@]}" -v nr="$((++nr))" -f process.awk
done
これにより、各ファイル名があり、コードがfname
セクションで実行されているかどうかをテストできます。nr==1
BEGIN
nr==tot
END
BEGIN {
if (nr==1) {
do BEGIN stuff
}
}
{ do common stuff }
END {
if (nr==tot) {
do END stuff
}
}
あるいは、一時ファイル用のスペースがある場合は、呼び出しを繰り返して、すべての出力をgpg
同じ名前のファイルの一時ディレクトリに書き込んでから、変更せずに各ファイルに対してawkを呼び出すこともできますprocess.awk
。
tmpdir=$(mktemp -d) &&
while IFS= read -r fname; do
gpg -d "$fname" > "$tmpdir"/"$fname"
done < <(find . -name '*.gpg') &&
awk -f process.awk "$tmpdir"/* &&
rm -rf "$tmpdir"