如何在Linux的shell中将一个文件追加到另一个文件中?

501

我有两个文件:file1file2。如何将file2的内容附加到file1中,以便file1的内容在此过程中保留不变?

8个回答

714

4
如果目标文件不属于你并且需要使用sudo,你该如何处理? - Bijay Rungta
1
@BijayRungta:听起来你已经回答了自己的问题。你需要在“cat”命令前加上“sudo”(如果提示输入凭据,则需输入)。 - David
你需要执行 chmod 777 /etc/default/docker 命令,以便在该文件上获得写入权限 - 执行完成后请务必恢复旧的文件权限。 - danday74
1
@Sigur:除非有一种方法可以同时将输出定向到两个文件中,否则它将涉及到两次命令的调用。 - David
3
你可以查看tee程序:cat 1 | tee -a 2 3。在--append(或简称为-a)开关后面可以加入任意数量的文件。 - Stefan van den Akker
显示剩余4条评论

321

cat file2 >> file1

>> 操作符将输出附加到指定的文件中,如果文件不存在则创建该文件。

cat file1 file2 > file3

这个命令可以将两个或多个文件合并成一个。您可以拥有任意数量的源文件。例如:

cat *.txt >> newfile.txt

更新于20130902
在评论中,eumiro建议"不要尝试cat file1 file2 > file1。”这样做可能不会得到预期的结果,因为在执行>左边的命令之前,接收重定向的文件被准备好了。在此情况下,首先将file1截断为零长度并打开以进行输出,然后cat命令尝试将现在的零长度文件和file2的内容连接到file1中。结果是丢失了file1的原始内容,并在其位置上放置了file2的副本,这可能不是预期的结果。

更新于20160919
在评论中,tpartee建议链接到支持信息/来源。对于官方参考资料,我向亲切的读者指出位于linuxcommand.org的sh man页面,其中写道:

在执行命令之前,可以使用一种特殊符号由shell解释来重定向命令的输入和输出。

虽然这告诉读者他们需要知道的内容,但如果您不是逐字逐句地查找并解析语句,很容易错过。最重要的单词在这里是'before'(之前)。重定向在执行命令之前完成(或失败)。

例如cat file1 file2 > file1的示例情况下,shell 首先执行重定向,以便在执行命令之前在环境中设置 I/O 句柄。

Ian Allen的网站提供了一个更友好的版本,其中详细介绍了重定向优先级,包括观察到即使没有命令也可以进行重定向的情况。将此传递给shell:

I/O Redirection Notes

$ >out

该命令会创建一个名为 out 的空文件。Shell 首先设置 I/O 重定向,然后查找命令,发现没有,然后完成操作。


18
@asir - 不要尝试使用cat file1 file2 > file1这个命令,它不会像你期望的那样工作。请注意不改变原意,并尽可能使语言更通俗易懂。 - eumiro
5
实际上,这正是他所需要的。他说:“不要覆盖当前的file1文件。”前三个回答者完全忽略了问题的这一部分,并建议使用“>>”命令,这会修改文件file1。T.Rob在解释他的答案时做得更好,而不仅仅是匆忙提交一个实际上是错误的内容。根据问题的文本,我认为cat file1 file2> file3是@asir正在寻找的适当命令。 - dm78
感谢您的赞美,David!eumiro上面指出的但没有详细说明的是,>右侧的操作会首先执行。因此,执行cat file1 file2 > file1将首先覆盖file1,然后尝试将现在长度为零的文件复制到自身。当您考虑操作应该发生的顺序时,这是有道理的,但足够微妙,以至于它会让很多人感到惊讶。因此,如果没有其他事情,eumiro和您已经促使了答案的进一步改进。感谢您! - T.Rob
同时,请不要尝试使用cat file1 >> file1,这将导致文件被递归重写。我曾经错误地这样做了,仅仅几秒钟内,就从之前的几十行中添加了5000万行到文件中。 - O.O
1
另外,为了更加简洁明了,如果“新文件”已经存在,则>>将向文件追加内容,而>则会替换文件。 - rinogo

51

注意: 如果需要使用 sudo,请执行以下操作:

sudo bash -c 'cat file2 >> file1'

通常的方法是将 sudo 直接添加到命令前,但这样做会失败,因为特权提升并不会传递到输出重定向中。


8
另一个常见的习语是 cat file2 | sudo tee -a file1 > /dev/null。这句话的意思是将 "file2" 的内容添加到 "file1" 中,并使用超级用户权限执行此操作,最后将输出重定向到 "/dev/null" 中。 - ianw

28

尝试使用这个命令:

cat file2 >> file1

14

仅供参考,使用ddrescue可以提供一种可中断的方式来完成任务,例如当您有大文件并需要在某个后续时间暂停然后继续进行时:

ddrescue -o $(wc --bytes file1 | awk '{ print $1 }') file2 file1 logfile

logfile是重要的一部分。你可以使用Ctrl-C打断过程,通过再次指定完全相同的命令并让ddrescue读取logfile来恢复它的进度。-o A标记告诉ddrescue从输出文件(file1)的第A个字节开始。所以,wc --bytes file1 | awk '{ print $1 }'只是提取file1的大小(如果你愿意,你也可以直接粘贴ls的输出)。

如评论中ngks所指出的那样,不好的一点是ddrescue可能不会默认安装,因此您需要手动安装它。另一个麻烦之处在于,你的存储库中可能有两个版本的ddrescue:请参阅这个askubuntu问题了解更多信息。你想要的版本是GNU ddrescue,在基于Debian的系统中的软件包名为gddrescue

sudo apt install gddrescue

对于其他发行版,请检查您的软件包管理系统以获取 GNU 版本的 ddrescue。


1
为了新用户的利益:ddrescue是GNU工具,但它可能不存在于您的Linux、Mac或其他类Unix系统中。ddrescue似乎不需要符合POSIX或任何其他标准。 - user2065875

7

另一种解决方案:

tee < file1 -a file2

tee有一个好处,就是可以将一个文件追加到多个文件中,例如:

tee < file1 -a file2 file3 file3

file1的内容追加到file2file3file4中。

与此相反的是

cat file2 file3 file4 >> file1

将多个文件追加到一个文件中的应用程序。

来自手册页面:

-a, --append
       append to the given FILEs, do not overwrite

0

Zsh 特定:您也可以不使用cat,但说实话cat更易读:

>> file1 < file2

>>STDIN附加到file1,而<file2转储到STDIN


6
它无法工作。 - user202729
1
@user202729 你说得对,在bash中不起作用。但在zsh中可以。 - Alok Singh

-1

cat 可以是简单的解决方案,但当我们连接大文件时,它会变得非常缓慢,find -print 就可以帮助你解救,尽管你必须使用一次 cat。

amey@xps ~/work/python/tmp $ ls -lhtr
total 969M
-rw-r--r-- 1 amey amey 485M May 24 23:54 bigFile2.txt
-rw-r--r-- 1 amey amey 485M May 24 23:55 bigFile1.txt

 amey@xps ~/work/python/tmp $ time cat bigFile1.txt bigFile2.txt >> out.txt

real    0m3.084s
user    0m0.012s
sys     0m2.308s


amey@xps ~/work/python/tmp $ time find . -maxdepth 1 -type f -name 'bigFile*' -print0 | xargs -0 cat -- > outFile1

real    0m2.516s
user    0m0.028s
sys     0m2.204s

你汇报的使用find/cat命令组合带来的时间节省是因为你只计时了输出文件名的find命令。尝试像这样计时整个命令:time (find . -maxdepth 1 -type f -name 'bigFile*' -print0 | xargs -0 cat -- > outFile1),它应该会产生与你仅使用cat命令相似的结果。 - JoshMc

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