我的目录中有很多文件:
$ ls
file000001
file000002
# ... truncated ...
file999999
我正在计算这样的文件的 md5sum 并最终将其转储到文件中:
hashes=''
for file in $(ls); do
hashes+=$(md5sum $file)
hashes+="\n"
done
echo "$hashes" > hashes.txt
现在,我想在循环内执行脚本时按 Ctrl + C for
,并将内容hashes
转储到 hashes.txt 文件中。这可能吗?
(是的,我可以在每次计算每个文件的 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
用作另一个程序的输入。它不起作用(对于任何包含可靠性或安全概念的“工作”定义),并且有绝不任何需要这样做,因为 shell 的通配符(即通配符扩展)完成了您试图通过误用ls
.看为什么不是解析ls
(以及该怎么做)?。
如果您必须做类似的事情,请使用find ... -exec {} +
或 而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
请注意,格式字符串中有两个
%s
由两个空格分隔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")
shell 将 的输出拆分为
md5sum
单词(由 shell$IFS
变量的值定义),并将每个“单词”放入数组的单独元素中。使用
tee
:$ hashes=( $( md5sum * | tee hashes.txt) ) $ cat hashes.txt b026324c6904b2a9cb4b88d6d61c81d1 file.1 26ab0db90d72e28ad0ba1e22ee510510 file.2 6d7fce9fee471194aa8b5b6e47267f03 file.3
知道了这一点,Lasse Kliemann 的陷阱答案可以写成:
trap ctrl_c INT
ctrl_c() {
printf '%s %s\n' "${hashes[@]}" > hashes.txt
exit 0
}
然而,你甚至不需要这里的陷阱。 md5sum
withtee
将执行您想要的操作 - 即同时填充$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
's -a
( --append
) 选项,因为我们md5sum
在循环中运行,并且不希望每次迭代都覆盖文件hashes.txt
。
注意:这将始终在字符串末尾有一个额外的空行$hashes
,从而将行数增加 1。使用数组时不会出现这种情况。