我有以下情况。一个包含很多子目录的目录,每个子目录都包含一个我想要连接的感兴趣的文件。 如,
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,然后将它们连接在一起?
答案 0 :(得分: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
,所以我在此处这样做。