我有一个名为 的文件夹simulations
,其中包含 101 个子文件夹。这些子文件夹被命名posterior_predictive_sim_1
为posterior_predictive_sim_101
.
每个子文件夹包含五个文件:seq.nex
、seq[1].nex
、seq[2].nex
、seq[3].nex
和seq[4].nex
。
我想从每个子文件夹中删除文件seq[1].nex
、seq[2].nex
、seq[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 内置命令,如for
或echo
。
另外,请使用/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
我建议用-ls
or运行它-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 的评论