
私のディレクトリにはたくさんのファイルがあります:
$ ls
file000001
file000002
# ... truncated ...
file999999
私はこのようなファイルのmd5sumを計算し、最終的にファイルにダンプします。
hashes=''
for file in $(ls); do
hashes+=$(md5sum $file)
hashes+="\n"
done
echo "$hashes" > hashes.txt
さて、ループ内でスクリプトを実行しながらCtrl + Cを押し、内容をhashes.txtファイルにダンプしたいとfor
思います。hashes
可能ですか?
(はい、各ファイルのmd5sumを計算するたびにmd5sumを追加できますが、hahes.txt
そうします(上記のように)。)
上記のサンプルコードはひどいです。私は実際にmd5sumを例として使用しています。私の質問の目的は、実際にCtrl + Cを操作する方法を見つけることです。
答え1
trap ctrl_c INT
ctrl_c() {
echo "$hashes" > hashes.txt
exit 0
}
ls
ところで、私はファイルのリストを取得するために使用しませんがfor file in *; do
。
答え2
trap break INT
ループ前:
hashes=
trap break INT
for file in *; do
hashes+=$(md5sum -- "$file")$'\n'
done
trap - INT
echo "$hashes" > hashes.txt
$(ls)
あなたのスクリプト(、)の疑わしい部分を修正しました"\n"
。
mksh
FWIW、これらの「非ローカル割り込み」はまたはでは動作しませんが、およびyash
では動作します。bash
dash
zsh
ksh93
答え3
ls
の出力を他のプログラムの入力として使用しないでください。 (信頼性や安全の概念を含む「動作」の定義について)うまくいかず、次の問題があります。いいえシェルのワイルドカード(ワイルドカード拡張など)は誤用で実行したいことを行うため、これを行う必要がありますls
。なぜいいえ解析ls
(および実行方法)?。
同様の作業を行う必要がある場合は、代わりにfind ... -exec {} +
orを使用してください。どちらかが実際に動作し、ファイル名にどの文字があっても安全に動作します。find ... -print0 | xargs -0r ...
ls
ループfor
は次のように書く必要があります。
for file in *; do
...
done
ループ内の各ループに対して異なる操作を実行しfor
たい場合を除き、ループは必要ありません。$file
以下は、forループ操作を実行し、出力を名前付きmd5sum
配列に保存してhashes
印刷するいくつかの代替方法です。
使用
printf
:$ hashes=( $( md5sum * ) ) $ printf '%s %s\n' "${hashes[@]}" > hashes.txt $ cat hashes.txt b026324c6904b2a9cb4b88d6d61c81d1 file.1 26ab0db90d72e28ad0ba1e22ee510510 file.2 6d7fce9fee471194aa8b5b6e47267f03 file.3
2つのフォーマット文字列は
%s
2つのスペースで区切られていますprintf
。これはそれ自体と同じ出力を生成しますmd5sum
。次のように、アイテムが配列にどのように保存されるかを確認できます
typeset -p
。$ typeset -p hashes declare -a hashes=([0]="b026324c6904b2a9cb4b88d6d61c81d1" [1]="file.1" [2]="26ab0db90d72e28ad0ba1e22ee510510" [3]="file.2" [4]="6d7fce9fee471194aa8b5b6e47267f03" [5]="file.3")
シェルは出力を
md5sum
単語($IFS
シェル変数の値として定義)に分割し、各「単語」を配列の別々の要素に入れます。使用
tee
:$ hashes=( $( md5sum * | tee hashes.txt) ) $ cat hashes.txt b026324c6904b2a9cb4b88d6d61c81d1 file.1 26ab0db90d72e28ad0ba1e22ee510510 file.2 6d7fce9fee471194aa8b5b6e47267f03 file.3
これを知ると、Lase Kliemannのトラップに対する答えは次のように書くことができます。
trap ctrl_c INT
ctrl_c() {
printf '%s %s\n' "${hashes[@]}" > hashes.txt
exit 0
}
しかし、ここでは罠すら必要ありません。 md5sum
withはあなたがtee
望むことを行います。つまり、$hashes
ANDhashes.txt
ファイルを同時に埋めます。
または配列を使用したくない場合:
$ for file in *; do
hashes+="$(md5sum "$file" | tee -a hashes.txt)"$'\n'
done
$ echo "$hashes"
b026324c6904b2a9cb4b88d6d61c81d1 file.1
26ab0db90d72e28ad0ba1e22ee510510 file.2
6d7fce9fee471194aa8b5b6e47267f03 file.3
ここでは、ループ内で実行され、繰り返しごとにファイルを上書きしたくないので、tee
' -a
(--append
)オプションを使用します。md5sum
hashes.txt
注:文字列の末尾には常に空白行が追加されているため、$hashes
行数は1ずつ増えます。配列を使用すると、これは発生しません。