在shell中删除具有相同md5sum的文件
Delete files with same md5sum in cshell
我正在尝试执行一项检查,其中所有具有相同 md5sum 的文件将被删除,保留第一次出现。
输入:第一列是md5值,第二列是文件名。
ab331f253704b84ae0aa5606adce4e7d 1.tcl
ab331f253704b84ae0aa5606adce4e7d 2.tcl
d86bbfda16f0d63ba35945e09dddce4d 3.tcl
1d0b140d16d32d2adbaa15643bdba412 4.tcl
8c97ae7965ae44ca6a4000d4e5988d54 5.tcl
ddf373efda3bbdf83d2dfa9cb7fc4d96 6.tcl
1d0b140d16d32d2adbaa15643bdba412 7.tcl
ddf373efda3bbdf83d2dfa9cb7fc4d96 8.tcl
输出:执行 rm -rf 2.tcl 7.tcl 8.tcl 因为存在具有相同 md5sum 的其他文件。
ab331f253704b84ae0aa5606adce4e7d 1.tcl
d86bbfda16f0d63ba35945e09dddce4d 3.tcl
1d0b140d16d32d2adbaa15643bdba412 4.tcl
8c97ae7965ae44ca6a4000d4e5988d54 5.tcl
ddf373efda3bbdf83d2dfa9cb7fc4d96 6.tcl
你有什么问题?算法或在 csh 中实现它?
如果您不寻求超快的操作,朴素的算法很简单:
在伪语言中:
for srcfile in sorted(list_of_files):
for tgtfile in list_of_files:
if srcfile != tgtfile and md5(srcfile) == md5(tgtfile):
delete tgtfile
我假设您的目标是从文本输入中删除某些行,而不是实际删除文件。
像这样:
awk '! seen[]++'
这是从标准输入读取的。如果输入在文件中,你可以这样做:
awk '! seen[]++' inputfile.txt
或者,如果它是某个命令的输出:
some_command | awk '! seen[]++'
说明:seen
是一个关联数组。 </code> 是当前行的第一个以空格分隔的字段。 <code>awk
逐行处理输入。 seen[]
告诉你当前行的第一个字段以前是否看过; ++
递增该值,将当前行标记为已在您下次看到时看到。递增一个不存在的数组元素将其设置为 1
.
这假设您的系统上安装了 awk
。你可能会。
如果您正在寻找纯 csh 的解决方案,而不调用外部命令,那将更加困难(而且我想不出这样做的充分理由)。
显然你真的想删除这些文件。这是一个解决方案:
awk '{ md5sum = ; file = ; if (seen[md5sum]++) { print "rm", file } }'
同样,您需要为此命令提供所需的输入。
这会打印但不会执行一系列 rm
命令。例如,给定问题的输入,输出为:
rm 2.tcl
rm 7.tcl
rm 8.tcl
您可以修改 awk
命令以使用 system("rm " file")
而不是仅打印它,但为了增加安全性,我会将输出写入文件,检查它看起来是否正确,然后source
删除文件的文件。使用根据任意输入自动删除文件的脚本很容易搬起石头砸自己的脚。
我正在尝试执行一项检查,其中所有具有相同 md5sum 的文件将被删除,保留第一次出现。
输入:第一列是md5值,第二列是文件名。
ab331f253704b84ae0aa5606adce4e7d 1.tcl
ab331f253704b84ae0aa5606adce4e7d 2.tcl
d86bbfda16f0d63ba35945e09dddce4d 3.tcl
1d0b140d16d32d2adbaa15643bdba412 4.tcl
8c97ae7965ae44ca6a4000d4e5988d54 5.tcl
ddf373efda3bbdf83d2dfa9cb7fc4d96 6.tcl
1d0b140d16d32d2adbaa15643bdba412 7.tcl
ddf373efda3bbdf83d2dfa9cb7fc4d96 8.tcl
输出:执行 rm -rf 2.tcl 7.tcl 8.tcl 因为存在具有相同 md5sum 的其他文件。
ab331f253704b84ae0aa5606adce4e7d 1.tcl
d86bbfda16f0d63ba35945e09dddce4d 3.tcl
1d0b140d16d32d2adbaa15643bdba412 4.tcl
8c97ae7965ae44ca6a4000d4e5988d54 5.tcl
ddf373efda3bbdf83d2dfa9cb7fc4d96 6.tcl
你有什么问题?算法或在 csh 中实现它?
如果您不寻求超快的操作,朴素的算法很简单:
在伪语言中:
for srcfile in sorted(list_of_files):
for tgtfile in list_of_files:
if srcfile != tgtfile and md5(srcfile) == md5(tgtfile):
delete tgtfile
我假设您的目标是从文本输入中删除某些行,而不是实际删除文件。
像这样:
awk '! seen[]++'
这是从标准输入读取的。如果输入在文件中,你可以这样做:
awk '! seen[]++' inputfile.txt
或者,如果它是某个命令的输出:
some_command | awk '! seen[]++'
说明:seen
是一个关联数组。 </code> 是当前行的第一个以空格分隔的字段。 <code>awk
逐行处理输入。 seen[]
告诉你当前行的第一个字段以前是否看过; ++
递增该值,将当前行标记为已在您下次看到时看到。递增一个不存在的数组元素将其设置为 1
.
这假设您的系统上安装了 awk
。你可能会。
如果您正在寻找纯 csh 的解决方案,而不调用外部命令,那将更加困难(而且我想不出这样做的充分理由)。
显然你真的想删除这些文件。这是一个解决方案:
awk '{ md5sum = ; file = ; if (seen[md5sum]++) { print "rm", file } }'
同样,您需要为此命令提供所需的输入。
这会打印但不会执行一系列 rm
命令。例如,给定问题的输入,输出为:
rm 2.tcl
rm 7.tcl
rm 8.tcl
您可以修改 awk
命令以使用 system("rm " file")
而不是仅打印它,但为了增加安全性,我会将输出写入文件,检查它看起来是否正确,然后source
删除文件的文件。使用根据任意输入自动删除文件的脚本很容易搬起石头砸自己的脚。