如何使用Unix的find、execute和cat命令将子目录中的文件连接成一个单独的文件?

10
我可以做到这一点:
$ find .
.
./b
./b/foo
./c
./c/foo

而这个:

$ find . -type f -exec cat {} \;
This is in b.
This is in c.

但不是这个:

$ find . -type f -exec cat > out.txt {} \;

为什么不呢?

1
您在标题中拼写“concatenate”错误了。 - Kip
8个回答

30

find命令的-exec参数会对每个找到的文件执行您指定的命令一次。尝试:

$ find . -type f -exec cat {} \; > out.txt
或者:
$ find . -type f | xargs cat > out.txt

xargs 将其标准输入转换为您指定的命令行参数。如果您担心文件名中嵌入的空格,请尝试:


xargs将输入作为参数传递给指定的命令,可以使用该命令来处理大量文件或目录。如果文件名包含空格等特殊字符,可以使用单引号或双引号将它们括起来,以避免被解释为多个参数。但是如果你使用了这种方法,你就必须手动输入每个文件名,而不是像xargs一样从标准输入读取。
$ find . -type f -print0 | xargs -0 cat > out.txt

1
我在使用Darwin操作系统,这可能是一个需要说明的限制。但是,使用某些方法时,我会得到一个循环行为,文件内容会无限地被追加。 - JR Lawhorne
是的,那是因为 out.txt 和 . 在同一个目录下;把 out.txt 放到外面的某个地方。 - dlamblin
没错,这就是解决方法。输出文件不能在你找到它的同一个目录中。 - JR Lawhorne

5

嗯...看起来find命令正在递归搜索,因为你将输出文件out.txt放在了当前目录下。

尝试使用以下命令:

find . -type f -exec cat {} \; > ../out.txt

3
你可以像这样做:
$ cat `find . -type f` > out.txt

只要find命令不找到太多文件,这个方法就可以工作。使用xargs命令来弥补。 - Martin York

2

既然你只想将所有文件合并成一个大文件,那么为什么不直接将find命令的输出重定向到一个文件中呢:

find . -type f -exec cat {} \; > /tmp/out.txt

1
也许你已经从其他回答中推断出,>符号在find获得它作为参数之前被shell解释了。但是为了回答你的“为什么不”,让我们看一下你的命令,它是:
$ find . -type f -exec cat > out.txt {} \;

所以你正在给 find 这些参数: "." "-type" "f" "-exec" "cat",你正在给重定向这些参数: "out.txt" "{}"";"。这使得 find 混淆了不使用分号终止 -exec 参数以及不将文件名作为参数("{}"),可能也会混淆重定向。

从其他建议来看,你应该真正避免在找到的同一目录中创建输出。但是如果考虑到这一点,它们仍然有效。而 -print0 | xargs -0 的组合非常有用。你想要键入的可能更像:

$ find . -type f -exec cat \{} \; > /tmp/out.txt

现在,如果您只有一个子目录级别和普通文件,您可以做一些愚蠢而简单的事情,例如:

cat `ls -p|sed 's/\/$/\/*/'` > /tmp/out.txt

这个命令使用ls列出所有文件和目录,并在目录后面添加'/',而sed则会在目录后面添加'*'。然后shell将解释此列表并扩展glob。假设这不会导致太多的文件供shell处理,那么这些文件都将作为参数传递给cat,并且输出将被写入out.txt。


将输出文件写入相同目录绝对是个问题。如果避免这样做,许多解决方案都能起作用。 - JR Lawhorne

0

或者,如果你使用非常好的 Z shell (zsh),可以省略查找操作,直接这样做:

setopt extendedglob

(这应该在你的.zshrc文件中)然后:

cat **/*(.) > outfile 

完美运行,:-)


0

试试这个:

(find . -type f -exec cat {} \;) > out.txt 

如果你将输出文件写入与查找文件不同的目录,它就可以工作了。 - JR Lawhorne

0

在Bash中,您可以这样做

cat $(find . -type f) > out.txt

使用 $( ) 可以获取命令的输出并将其传递给另一个命令。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接