Shell - Cat - 合并多个文件内容到一个大文件中

13

我正在尝试使用bash将一个文件列表(多达1K)中的内容合并到一个大文件中。

我已经尝试了以下cat命令:

cat * >> bigfile.txt
然而,该命令所做的是合并所有内容,包括已经合并的内容。
例如:file1.txt
content1

文件2.txt

content2

文件3.txt

content3

文件名为file4.txt

content4

大文件.txt

content1
content2
content3
content2
content3
content4
content2

但我只想要

content1
content2
content3
content4

文本文件内部

另一种方法是cat file1.txt file2.txt ...等等...但我不能用这种方法处理超过1000个文件!

感谢您的支持!

6个回答

25
问题在于您将bigfile放在同一个目录中,因此使其成为*的一部分。 因此,类似以下内容:
cat dir/* > bigfile

只要您想要的是这样,在位于dir/fileN.txt文件中它应该可以正常工作。


1
...或者 cat * >/tmp/bigfile; mv /tmp/bigfile . - tripleee
我认为fabioln故意在输入中包含bigfile.txt; 他想从各个file*.txt文件中添加到该文件,同时消除重复项。 - chepner
谢谢大家。是的,那就是问题所在!我把bigfile放在同一个目录下...所以我使用了你给我的命令(cat dir/* > bigfile)!只有一个问题:为什么你只用了>而不是>>,这两个符号是一样的吗?谢谢! - fabioln79
@fabioln79 使用 >> 将输出附加到文件中,使用 > 覆盖整个内容。 - mvds
在合并文件时,我们是否总是可以依赖于“星号符号”来保证正确的顺序? - Chris K
1
取决于你所定义的“正确”顺序,Shell 会按照字母顺序扩展 *。详见 https://serverfault.com/a/122743 - mvds

4

重新阅读你的问题后,看起来你想要将数据追加到bigfile.txt中,但是不添加重复项。你需要通过sort -u来过滤掉重复项:

sort -u * -o bigfile.txt
-o选项可以让你在覆盖输出文件之前,安全地将bigfile.txt的内容包含在sort命令的输入中。
编辑:假设bigfile.txt已经排序好了,你可以尝试使用两个阶段的过程:
sort -u file*.txt | sort -um - bigfile.txt -o bigfile.txt

首先,我们对输入文件进行排序并去除重复项。然后将该输出管道传输到另一个 sort -u 进程中,此进程还使用了 -m 选项,告诉 sort 合并两个已经排序的文件。我们将要合并的两个文件是 -(标准输入,来自第一个 sort 的流)和 bigfile.txt 本身。我们再次使用 -o 选项,允许我们在读取它作为输入后将输出写回到 bigfile.txt 中。


我已经修改了答案,允许将新数据合并到bigfile.txt中,使其保持排序且不引入重复项。我认为这是在不切换到更结构化格式(如数据库)的情况下所能做到的最好的方法。 - chepner

4
您可以将输出文件保留在同一目录中,只需比“*”符号更加复杂即可:
shopt -s extglob
cat !(bigfile.txt) > bigfile.txt

谢谢。我有一个与此命令相关的问题:包含该文件的目录大小为557GB,但创建的bigfile大小为495。我不知道如何解释这个问题。我做错了什么吗?谢谢! - fabioln79
根据提供的信息,怀疑这可能是由于实际使用的空间与块大小不符(请了解后者)。@fabioln79 - user66001

2
另外一种方法是使用“cat file1.txt file2.txt ...”等命令,但如果有超过1000个文件则无法执行!这时候就需要用到xargs命令:
find . -maxdepth 1 -type f -name "file*.txt" -print0 | xargs -0 cat > bigfile.txt

xargs会为每个参数执行命令吗?如果是这样,应该使用'>>'而不是'>'吗?我想当它完成时,bigfile.txt将只包含传递给它的最后一个文件的内容。 - JerseyMike
1
xargs 对于所有参数只运行一次命令,您不需要使用 '>>' - Barton Chittenden
谢谢您的澄清。对我来说,手册上并不是很清楚。 - JerseyMike

1

这是一个旧问题,但我仍然会提供另一种使用 xargs 的方法

  1. 列出您想要连接的文件

    ls | grep [pattern] > filelist

  2. 使用 vicat 检查您的文件是否按正确顺序排列。如果您使用后缀(1、2、3、...、N),则不应该有问题

  3. 创建最终文件

    cat filelist | xargs cat >> [final file]

  4. 删除 filelist 文件

    rm -f filelist

希望这对任何人有所帮助


-3

尝试:

cat `ls -1 *` >> bigfile.txt

目前我手头没有Unix机器可以先为您测试。


2
-1 这并没有解决任何问题,反而引入了一些新的问题。当通配符已经扩展到你想要的文件时,不要使用 ls!不要使用未加引号的文件名(来自反引号的输出),因为如果文件名包含空格,它会出错。 - tripleee
我在写那段代码时,其实是想用循环的,但是没有表达清楚。不过,我还是更喜欢Barton的答案。 - JerseyMike

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