在Bash中将多个文本文件连接成一个单一文件

429

最快、最实用的方法是将目录中所有*.txt文件合并成一个大文本文件?

目前我正在使用带有Cygwin的Windows,因此我可以访问BASH。

Windows shell命令也不错,但我怀疑是否存在这样的命令。

12个回答

752

这将把输出添加到all.txt文件中。

cat *.txt >> all.txt

这将覆盖all.txt文件。

cat *.txt > all.txt

44
你可能会遇到这样一个问题,即它将all.txt文件复制到all.txt文件中......我有时用grep命令也会遇到这个问题,不确定cat命令是否有相同的行为。 - rmeador
13
是的,如果all.txt已经存在,您将面临这个问题。通过为输出文件提供不同的扩展名或将all.txt移动到另一个文件夹来解决这个问题。 - Robert Greiner
6
将所有以".txt"结尾的文件内容合并到一个名为"tmp"的文件中,然后将该文件重命名为"all.txt",请确保在执行此操作之前不存在名为"all.txt"的文件。 - Renaud
19
我收到了"Argument list too long"的错误提示,猜测是因为无法处理超过40,000个文件。 - Matt
40
使用以下命令避免参数列表过长的问题:echo *.txt | xargs cat > all.txt。该命令将使用通配符选择所有以“.txt”结尾的文件,并使用xargs命令将它们传递给cat命令,最终将它们合并到一个名为“all.txt”的文件中。 - 5heikki
显示剩余6条评论

208

请记住,对于迄今为止给出的所有解决方案,shell 决定了连接文件的顺序。对于 Bash,如果我没有记错的话,这是按字母顺序排序的。如果顺序很重要,您应该适当地命名文件(01file.txt、02file.txt 等),或指定您想要连接的每个文件的顺序。

$ cat file1 file2 file3 file4 file5 file6 > out.txt

33

Windows中的shell命令type可以实现这个功能:

type *.txt > outputfile.txt

type命令还会将文件名写入stderr,这些内容无法被>重定向操作符捕获(但会显示在控制台上)。


3
请注意,如果您将输出文件放在与原始文件相同的目录中,将会导致重复,因为它也会将新的输出文件合并两次。 - CathalMF
8
用户请求 Bash。 - capdragon

30

你可以使用 Windows 命令行的 copy 命令来连接文件。

C:\> copy *.txt outputfile

从帮助文件中得知:

若要将多个文件追加到一个目标文件中,指定目标文件为单个文件,源文件为多个文件(使用通配符或file1+file2+file3格式)。


这是我个人认为最干净的解决方案,基本上没有副作用,但是很不幸,初学者可能会被忽视 :-( - Grmpfhmbl
OP 要求使用 Bash。 - Big Rich
5
你读到这个问题了吗?“Windows shell命令也很好…” - Carl Norum
工作得相当不错,只是在我的文件末尾出现了一个奇怪的SUB特殊Unicode字符。从程序上很容易删除它,但不确定为什么会出现这种情况。 - abelito

19

请注意,这些方法都无法处理大量文件。个人而言,我使用了以下命令行:

for i in $(ls | grep ".txt");do cat $i >> output.txt;done

编辑:正如评论中有人所说,您可以使用$(ls *.txt)替换$(ls | grep ".txt")

编辑:由于@gnourf_gnourf 的专业知识,使用glob是在目录中迭代文件的正确方式。因此,像$(ls | grep ".txt")这样的亵渎性表达式必须被*.txt取代(请参见这里的文章)。

好的解决方案

for i in *.txt;do cat $i >> output.txt;done

2
为什么不使用 for i in $(ls *.txt);do cat $i >> output.txt;done 呢? - streamofstars
3
必须包含 ParsingLs的链接,并附带一个踩的标记(你应该得到多个踩的标记,因为"ls | grep"是一个严重的反范式)。 - gniourf_gniourf
我给你点赞是因为它允许在输出之前通过文件名进行任意测试/操作,而且它快速、简单,非常适合练习。 (在我的情况下,我想要:for i in *; do echo -e "\n$i:\n"; cat $1; done) - Nathan Chappell
1
如果有太多的文件(参数列表过长错误),ls *.txt不会失败吗? - Rafael Almeida
@强制执行:ls *.txt | grep .txt | awk '/.txt/' LOL - runlevel0

18

这种方法怎么样?

find . -type f -name '*.txt' -exec cat {} + >> output.txt

由于 OP 表示文件在同一目录中,您可能需要在 find 命令中添加 -maxdepth 1 - codeforester
3
适用于大量文件的情况,而传统方法失败的地方,它表现出色。 - amine
啊,我希望我知道这个加号和双重重定向符号代表什么... - hello_earth
这应该是正确的答案。它将在shell脚本中正常工作。如果您想要排序输出,可以使用类似的方法:sort -u --output="$OUTPUT_FILE" --files0-from=- < <(find "$DIRECTORY_NAME" -maxdepth 1 -type f -name '*.txt' -print0) - steveH
这是一种非常灵活的方法,依赖于find的所有优点。我最喜欢的!当然,cat *.txt > all.txt可以在同一个目录中完成工作(如上所述)。然而,对我来说,熟练地使用find已经成为了一个非常好的习惯。今天它们都在一个文件夹中,明天它们可能会跨越嵌套的目录层次结构具有多个文件扩展名。不要过度复杂化,但也要与find成为朋友。 :) - nJGL

7

在IT技术中,最实用的命令之一是cat命令。其他方法包括:

awk '1' *.txt > all.txt
perl -ne 'print;' *.txt > all.txt

1
这应该是大多数情况下的正确答案。 如果任何文本文件没有空的新行,使用上述所有cat方法将连接相邻文件的最后一行和第一行。 - mootmoot

3
type [source folder]\*.[File extension] > [destination folder]\[file name].[File extension]

例如:

type C:\*.txt > C:\1\all.txt

这将获取C:\文件夹中的所有txt文件,并以all.txt的名称保存在C:\1文件夹中。

或者

type [source folder]\* > [destination folder]\[file name].[File extension]

例如:
type C:\* > C:\1\all.txt

那将获取文件夹中所有的文件,并将它们的内容放入 C:\1\all.txt 中。

1
你可以这样做: cat [directory_path]/**/*.[h,m] > test.txt 如果你使用 {} 来包含你想要查找的文件扩展名,会出现顺序问题。

1

如果文件列表过长,最受欢迎的答案将会失败。

更便携的解决方案是使用fd

fd -e txt -d 1 -X awk 1 > combined.txt

-d 1选项将搜索限制在当前目录。如果省略此选项,则会从当前目录递归查找所有.txt文件。
-X(也称为--exec-batch)一次性为所有搜索结果执行一个命令(在本例中为awk 1)。

请注意,fd不是“标准”的Unix程序,因此您可能需要安装它。


“bash: fd: command not found” 这个错误提示意味着你需要自己安装 fd 包。 - Dem Pilafian
我在答案中已经链接到它,但我会更加明确。 - Michael Hall

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