将多个文件连接在一起,但包含文件名作为节标题

478

我想在终端中将多个文本文件连接成一个大文件。我知道可以使用cat命令来完成此操作。但是,我希望在每个文件的“数据转储”之前加上该文件的文件名。有人知道如何做到这一点吗?

我目前拥有的:

file1.txt = bluemoongoodbeer

file2.txt = awesomepossum

file3.txt = hownowbrowncow

cat file1.txt file2.txt file3.txt

期望的输出:

file1

bluemoongoodbeer

file2

awesomepossum

file3

hownowbrowncow

我实际上正在使用uuencode和uudecode来做类似的事情,我不需要在中间可读的文件,只需要结果并将它们再次传输到另一个命令。 - user2304417
3
展示多个文件的内容。在Unix/Linux系统中,使用"cat"命令可以用来显示一个文件的内容。如果需要同时显示多个文件的内容,可以在"cat"命令后面跟上需要显示内容的文件名列表。例如:cat file1.txt file2.txt file3.txt这个命令会依次显示file1.txt、file2.txt和file3.txt文件的内容。如果需要将所有文件的内容输出到一个文件中,可以使用重定向符号">",例如:cat file1.txt file2.txt file3.txt > allfiles.txt这条命令会将file1.txt、file2.txt和file3.txt文件的内容输出到allfiles.txt文件中。 - Ciro Santilli OurBigBook.com
bat是一个很好的替代品,当你只想查看多个文件内容时,它可以替代cat - Nicolai Weitkemper
21个回答

722

我也在寻找同样的内容,发现这个可以建议:

tail -n +1 file1.txt file2.txt file3.txt

输出:

==> file1.txt <==
<contents of file1.txt>

==> file2.txt <==
<contents of file2.txt>

==> file3.txt <==
<contents of file3.txt>

如果只有一个文件,则不会打印标题。如果使用GNU工具,您可以使用-v始终打印标题。


2
这也适用于GNU尾部(GNU Coreutils的一部分)。 - ArjunShankar
18
太棒了,-n +1 选项!另一种替代方法是 head -n-0 file1 file2 file3 - Frozen Flame
6
在MacOS X上,无论是BSD tail还是GNU tail,都可以很好地运作。您可以省略-n+1之间的空格,例如使用-n+1 - vdm
7
tail -n +1 * 恰好是我正在寻找的,谢谢! - kR105
2
适用于MacOsX 10.14.4 sudo ulimit -n 1024; find -f . -name "*.rb" | xargs tail -n+1 > ./source_ruby.txt - kolas
显示剩余8条评论

247

我曾使用grep来处理类似的事情:

grep "" *.txt

这不会给你一个“标题”,但会在每一行前缀上文件名。


16
如果*.txt只展开为一个文件,则输出会中断。在这方面,我建议使用grep'' /dev/null *.txt - antak
2
+1,因为向我展示了grep的新用途。这完美地满足了我的需求。在我的情况下,每个文件只包含一行,因此它给了我一个整洁格式的输出,很容易解析。 - verboze
11
如果存在多个文件,grep 将只打印文件头。如果您想始终打印文件路径以确保输出的完整性,请使用 -H。如果您不想打印文件头,请使用 -h。请注意,对于标准输入,它将打印 (standard input) - Jorge Bucaran
1
您还可以使用ag(银色搜索器):默认情况下,ag . *.txt会在每个文件前缀中添加其名称,并在每行前缀中添加其编号。 - anol
1
值得注意的是,将“-n”传递给grep还会产生行号,这使您可以编写简单的代码检查工具,并且可以被例如emacs等编辑器捕获。 - DepressedDaniel
显示剩余2条评论

134
这个也能起到同样的效果:
$ find . -type f -print -exec cat {} \;
./file1.txt
Content of file1.txt
./file2.txt
Content of file2.txt

这里是命令行参数的解释:
find    = linux `find` command finds filenames, see `man find` for more info
.       = in current directory
-type f = only files, not directories
-print  = show found file
-exec   = additionally execute another linux command
cat     = linux `cat` command, see `man cat`, displays file contents
{}      = placeholder for the currently found filename
\;      = tell `find` command that it ends now here

您可以通过布尔运算符如-and-or进一步组合搜索。 find -ls也很好用。

2
你能否解释一下这个命令的作用?这正是我所需要的。 - AAlvz
5
这是 Linux 的标准 find 命令。它会搜索当前目录中的所有文件,并打印它们的名称,然后对于每个文件,使用 cat 命令输出其内容。如果省略 -print 参数,则 cat 命令不会在输出之前打印文件名。 - Maxim_united
20
你还可以使用-printf自定义输出。例如: find *.conf -type f -printf'\n==> %p <==\n' -exec cat {} \;以匹配tail -n +1 *的输出结果。 - Maxim_united
1
-printf 在 Mac 上无法使用,除非您想要 brew install findutils 然后使用 gfind 代替 find - Matt Fletcher
2
如果你想要颜色,你可以利用 find 命令允许多个 -exec 的特性:find -name '*.conf' -exec printf '\n\e[33;1m%s\e[0m\n' {} \; -exec cat {} \; - banbh
显示剩余3条评论

30

当有多个输入文件时,more命令将它们连接起来,并在每个文件名上加上一个头。

要连接到一个文件:

more *.txt > out.txt
在终端中进行连接操作:
more *.txt | cat

示例输出:

::::::::::::::
file1.txt
::::::::::::::
This is
my first file.
::::::::::::::
file2.txt
::::::::::::::
And this is my
second file.

对于我自己,我必须使用以下命令:String="${String//$'\n'::::::::::::::$'\n'/|}" 然后:String="${String//::::::::::::::$'\n'/}" 最后:String="${String//$'\n'/|}" 将其转换为 YAD 数组:IFS='|' read -ra OLD_ARR <<< "$String" - WinEunuuchs2Unix
@Acumenus 首先我需要使用以下命令构建字符串字段:String=$(sudo -u "$SUDO_USER" ssh "$SUDO_USER"@"$TRG_HOST" \ "find /tmp/$SUDO_USER/scp.*/*.Header -type f \ -printf '%Ts\t%p\n' | sort -nr | cut -f2 | \ xargs more | cat | cut -d'|' -f2,3" \ ) - WinEunuuchs2Unix
@WinEunuuchs2Unix 我没听懂。如果您愿意,可以在 https://gist.github.com/ 上更清楚地解释,并提供链接。 - Asclepius
@Acumenus,等我完成后,最好将脚本上传到 GitHub 上。它只是使用sudo复制根文件在主机之间,因为主机没有root账户。注释中的代码是用来选择以前负载的头文件的。这是一种边缘情况,不会引起大多数用户的兴趣。 - WinEunuuchs2Unix
1
这在我的MacOS上不起作用。我只能得到文件内容。 - ben-albrecht
好棒的技巧。我得到了我需要的输出。谢谢。 - sourabh kesharwani

28
这应该可以解决问题:
for filename in file1.txt file2.txt file3.txt; do
    echo "$filename"
    cat "$filename"
done > output.txt

或者递归地对所有文本文件执行此操作:

find . -type f -name '*.txt' -print | while read filename; do
    echo "$filename"
    cat "$filename"
done > output.txt

1
没有起作用。我刚刚写了一些非常丑陋的awk代码: for i in $listoffiles do awk '{print FILENAME,$0,$1,$2,$3,$4,$5,$6,$7,$8,$9,$10,$11}' $i >> concat.txt done - Nick
2
能详细说明一下吗?这已经是最简单的Bash代码了。 - Chris Eberle
1
@Nick:你的awk命令行甚至不应该起作用,因为$0是整行,所以你实际上在重复列... - Chris Eberle
@jayunit100:无限循环发生在目标文件与通配符匹配的情况下。请将其命名为不匹配的名称。 - rshetye
我喜欢这种方法,因为它可以更灵活地呈现输出! - Matt Fletcher
显示剩余4条评论

15
find . -type f -print0 | xargs -0 -I % sh -c 'echo %; cat %'

这将打印完整的文件名(包括路径),然后是文件的内容。它也非常灵活,因为您可以在find命令中使用“-name”和“expr”,并对文件运行任意多个命令。


2
grep 结合使用也非常简单。在 bash 中使用:find . -type f -print | grep PATTERN | xargs -n 1 -I {} -i bash -c 'echo ==== {} ====; cat {}; echo' - dojuba

7

缺失的awk解决方案如下:

$ awk '(FNR==1){print ">> " FILENAME " <<"}1' *

谢谢你的出色回答。你能解释一下表达式末尾的 1 的含义吗? - bwangel
1
谢谢。您可以查看awk脚本末尾的1是什么意思 - kvantour
awk '{ if (FNR == 1) print "==>" FILENAME "<=="; print }' *.txt,使用 print1 更好。而 awk '{ if (FNR == 1) print "\033[31m==>" FILENAME "<==\033[0m" > "/dev/stderr"; print }' *.txt 可以将文件名带有颜色地输出到 stderr - Míng
@Mr.Míng 这个评论没有提供任何额外的价值。此外,整个操作语句违反了语言语法的理念。 - kvantour
@kvantour确实,我对这种意识形态并不了解,但我认为print1更易读,特别是对于像bwangel和我这样的人来说。 - Míng

6
这是我通常处理这样格式的方法:

这是我通常处理这样格式的方法:

for i in *; do echo "$i"; echo ; cat "$i"; echo ; done ;

一般来说,我会将cat的输出结果通过grep命令筛选出特定的信息。

3
注意了,这里的 for i in * 不会包括子目录。 - Asclepius

5

我喜欢这个选项

for x in $(ls ./*.php); do echo $x; cat $x | grep -i 'menuItem'; done

输出结果如下:

./debug-things.php
./Facebook.Pixel.Code.php
./footer.trusted.seller.items.php
./GoogleAnalytics.php
./JivositeCode.php
./Live-Messenger.php
./mPopex.php
./NOTIFICATIONS-box.php
./reviewPopUp_Frame.php
            $('#top-nav-scroller-pos-<?=$active**MenuItem**;?>').addClass('active');
            gotTo**MenuItem**();
./Reviews-Frames-PopUps.php
./social.media.login.btns.php
./social-side-bar.php
./staticWalletsAlerst.php
./tmp-fix.php
./top-nav-scroller.php
$active**MenuItem** = '0';
        $active**MenuItem** = '1';
        $active**MenuItem** = '2';
        $active**MenuItem** = '3';
./Waiting-Overlay.php
./Yandex.Metrika.php

4
如果文件都有相同的名称或可以通过find进行匹配,您可以执行以下操作(例如):
find . -name create.sh | xargs tail -n +1

查找、显示文件路径并将每个文件内容输出。


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