我有以下情况。一个包含大量子目录的目录,每个子目录都包含一个我想要连接的感兴趣文件。 例如,
my_dir/
subdir1/
subsubdir/
file_of_interest1.txt
...
subdir2/
subsubdir/
file_of_interest1.txt
...
...
现在,我尝试使用cat my_dir/*/*/*.txt > all.txt
但不幸的是,子目录树太大了,以至于我收到以下错误:
bash: /bin/cat: Argument list too long
有没有一种聪明的方法来规避这个问题,例如,通过将文件连接成更小的块? 例如,连接 1/3 的子目录,然后连接另一个 1/3 和 1/3,然后将它们全部连接在一起?
find
浏览文件,并尽可能多地添加到每个cat
调用的命令行中:
find . -type f -name '*.txt' -exec cat '{}' + >all.txt
如果你的find
不支持-exec ... {} +
(如果符合当前版本的POSIX规范,它应该支持),还有一种方法使用GNU扩展来使xargs安全:
find . -type f -name '*.txt' -print0 | xargs -0 cat >all.txt
使用不带-0
的 xargs 是不安全的——在这种情况下,它不能正确处理带有换行符的文件名,以及其他问题(其中一些但不是全部可以通过其他选项避免)。考虑恶意用户创建文件$'foo n/etc/passwd'
- 您不想冒将/etc/passwd
注入输出的风险。
最后,还有一种效率较低、较旧的find -exec
使用方法(它为每个找到的文件调用单独的cat
副本):
find . -type f -name '*.txt' -exec cat '{}' ';' >all.txt
。或者,在类似的惩罚(多次调用cat
)下,您可以简单地在 shell 脚本中使用循环:
for f in my_dir/*/*/*.txt; do
cat "$f"
done >all.txt
请注意,这会在整个循环上执行重定向,而不是(效率较低)基于每个文件。
旁白:如果使用 POSIX sh 或 bash,则无需引用{}
。但是,如果尝试支持zsh
,您确实需要引用{}
,所以我在这里这样做。