我有一个图像文件夹,其中包含相当多的重复项,我想删除除一个之外的所有重复项。
通过谷歌搜索,我发现了这个聪明的脚本这个帖子简洁地说几乎我想要它做什么:
#!/bin/sh -eu
find "${1:-.}" -type f ! -empty -print0 | xargs -0 md5 -r | \
awk '$1 in a{sub("^.{33}","");printf "%s\0",$0}a[$1]+=1{}' | \
xargs -0 rm -v --
不幸的是,我对 UNIX shell 脚本还很陌生,所以我不确定每个部分的实际命令/标志在这里做什么,所以我无法根据我的特定需求对其进行修改。
据我了解:
find "${1:-.}" -type f ! -empty -print0
- 搜索当前目录中的非空文件并打印文件名。 (虽然不确定这首曲子的"${1:-.}"
意思)
| xargs -0 md5 -r
- 将上面的结果(通过xargs -0
命令?)传送到md5
命令中以获取每个文件的 md5 哈希签名(-r
反转输出以使其成为单行?)
awk '$1 in a{sub("^.{33}","");printf "%s\0",$0}a[$1]+=1{}'
- 这就是我迷路的地方..
$1 in a{sub("^.{33}","")
- 获取输入直到第一个空白字符,并将字符串开头的前 33 个字符替换为空 (sub("^.{33}",""
)printf "%s\0"
- 格式打印整个字符串a{...,$0}
- 我不知道这是做什么的a[$1]+=1{}
- 也不确定
xargs -0 rm -v --
- 将结果通过管道传输到rm
命令,通过 打印每个文件名-v
,但我不确定语法--
的用途。
当我运行它时,它输出如下,./test3.jpg./test2.jpg./test.jpg: No such file or directory
所以一定存在格式问题。
我的问题是:
- 可以修改它以删除除 1 之外的所有文件吗?
- 有人可以帮助解释我上面概述的命令/语法含义之间的差距吗?
我相信这对于熟悉 UNIX 的人来说可能很容易,但不幸的是那个人不是我。提前谢谢您!
对于上下文:我在 macOS BigSur 11 的 ZSH 中运行它。
答案1
我将重点关注awk
这里的 - 部分:
md5 -r
返回 32 个字符的 md5-sum,然后返回文件名。因此 md5-sum 是 中的第一个字段awk
。
$1 in a{...}
意思是“如果$1
(这里:md5-sum)被发现作为数组中的索引,a
则执行命令{...}”。因此a
将被用作一个数组,其中 md5 和作为已经看到的索引。请注意,如果该值不存在或为 0,则不会执行该命令 - 因此第一次看到 md5-sum 时,文件名是不是回。如果它是任何其他值(包括字符串),则条件为 true,并且执行命令。
sub("^.{33}","");printf "%s\0",$0
将从开头删除 33 个字符,即 md5-sum 和后面的空格,然后打印其余部分(原始文件名),末尾带有 NUL 分隔符。 NUL 分隔对于带有空格等的文件很重要。参见-print0
中man find
或-0
中man xargs
。请注意,仅当 md5-sum 已在 array 中时才运行此命令a
,因此不会返回第一个匹配项(即仅显示重复项,稍后将其删除)。
a[$1]+=1{}
“数组的元素$1加1 a
”,$1是md5-sum。因此,a
一旦看到 md5-sum,就会设置该值。这是重复计数器。 '{}' 是空命令。这是必要的,因为awk
默认情况下,如果满足条件且未给出命令,则返回完整记录。
警告
据我所知,该脚本对于带有空格的文件工作正常,但我认为对于名称中带有换行符的文件来说它会失败,因为awk
没有将 NUL 设置为记录分隔符,然后将默认为换行符。BEGIN {RS="\x0"}
首先使用inawk
进行设置。