如何从命令行删除多个子文件夹中的同名文件?

如何从命令行删除多个子文件夹中的同名文件?

我有一个名为 的文件夹simulations,其中包含 101 个子文件夹。这些子文件夹被命名posterior_predictive_sim_1posterior_predictive_sim_101.

每个子文件夹包含五个文件:seq.nexseq[1].nexseq[2].nexseq[3].nexseq[4].nex

我想从每个子文件夹中删除文件seq[1].nexseq[2].nexseq[3].nex、 和seq[4].nex(以便仅seq.nex保留)。

我如何从命令行执行此操作?

答案1

只需rm

rm simulations/posterior_predictive_sim_*/seq\[[1-4]\].nex

转义的\[and\]是字面方括号。其中未转义的内容[1-4]是与数字 1 到 4 匹配的 glob 模式。

仅当 glob 扩展的文件名数量不超过一个命令行所能容纳的数量时,这才有效,ARG_MAX限制 - 这取决于操作系统,但在现代 Linux 上约为 200 万个字符。 ARG_MAX 适用于外部命令,如rm,而不适用于 shell 内置命令,如forecho

另外,请使用/bin/echo而不是rm首先进行测试。因为: 1. /bin/echo 是安全的,不会删除任何东西。 2./bin/echo是一个外部命令,不是 shell 内置版本的 echo,因此还将测试总命令长度是否 <= ARG_MAX。

使用 GNU find

find simulations/ -type f -name 'seq\[[1-4]\].nex' -delete

我建议用-lsor运行它-print 使用-delete(或-exec rm如下)运行它,只是为了验证它是否会执行您想要的操作。

或者:

find simulations/ -type f -name 'seq\[[1-4]\].nex' -exec rm {} +

某些古老版本的 find 不支持+谓词末尾-exec,因此请改用\;

find simulations/ -type f -name 'seq\[[1-4]\].nex' -exec rm {} \;

+和之间的区别\;在于,使用 时,find 尝试将尽可能+多的文件名参数放入命令中(再次是 ARG_MAX)。rm使用\;,它rm每个文件名运行一次 - 这显然是很多速度较慢,但​​它仍然有用(例如,当您需要运行一个仅采用一个文件名参数的程序时)。

顺便说一句,\;对于 来说并不特别find。事实上,find它本身仅用作;的终止符-exec。这\是为了确保 shell 将分号传递给find,即防止 shell 将 解释;为语句的结尾find。 shell 语句由换行符或分号分隔。

答案2

首先您需要文件列表。您可以使用ls, find, fd... 将其保存到文本文件:ls posterior_predictive_sim_*/ > all.txt.人们抱怨解析 ls, tl;dr 在这里并不重要。

然后你想过滤掉那些你真正想要删除的文件:(cat all.txt | grep -v 'seq.nex' > del.txt你也可以尝试让你的 shell 接受更保守的正则表达式模式seq[\d+]\.nex)。

现在打开del.txt并检查您是否确实要删除所有内容。如果需要,您可以手动编辑该文件。

最后,实际删除它们。rm可以一次获取多个文件名,因此除非您有数千个文件,否则您可以尝试这样做。我喜欢使用 GNU Parallel: cat del.txt | parallel --dry-run rm {}。它将打印它计划运行的实际命令,删除--dry-run以真正执行它。

如果您喜欢生活在边缘,您还可以将所有这些命令通过管道传递给彼此,而不是将它们保存到文件中。希望您没有犯错误,rm文件无法恢复。顺便说一句使用https://github.com/andreafrancia/trash-cli相反,它可以让您取消删除文件。

答案3

用循环:

for i in $(ls); do rm posterior_predictive_sim_$i/seq\[*.nex; done


留下这一点只是为了提醒自己和其他人为什么不这样做 - 请参阅下面 cas 的评论

相关内容