连接文件,在它们之间放置一个空行

Gig*_*iux 7 files cat newlines

我有一堆具有相同扩展名的文件(比如 .txt),我想将它们连接起来。我正在使用cat *.txt > concat.txt,但我想在每个文件之间添加一个新行,以便在 concat.txt 中区分它们。

是否有可能用一个单一的bash命令,而不是这样的实现做这个

谢谢

ter*_*don 9

不是一个命令,而是一个简单的单行:

for f in *.txt; do cat -- "$f"; printf "\n"; done > newfile.txt
Run Code Online (Sandbox Code Playgroud)

这将给出此错误:

cat: newfile.txt: input file is output file
Run Code Online (Sandbox Code Playgroud)

但是你可以忽略它,至少在 GNU/Linux 系统上是这样。Stéphane Chazelas 在评论中指出,显然,在其他系统上,这可能会导致无限循环,因此要避免它,请尝试:

for f in *.txt; do 
    [[ "$f" = newfile.txt ]] || { cat -- "$f"; printf "\n"; }
done > newfile.txt
Run Code Online (Sandbox Code Playgroud)

或者只是不要.txt向输出文件添加扩展名(它不需要并且根本没有任何区别,无论如何),这样它就不会包含在循环中:

for f in *.txt; do cat -- "$f"; printf "\n"; done > newfile
Run Code Online (Sandbox Code Playgroud)

  • 并非所有“cat”实现都会告诉您*输入文件是输出文件*。其他一些人会很乐意在这里运行,可能会导致无限循环,从而填满文件系统。 (2认同)

Kus*_*nda 7

使用 GNU sed

sed -s -e $'$a\\\n' ./*.txt >concat.out
Run Code Online (Sandbox Code Playgroud)

这将连接所有数据,concat.out同时在处理的每个文件的末尾附加一个空行。

-sGNU的选项sed使$地址匹配每个文件的最后一行,而不是像往常一样,所有数据的最后一行。该a命令在给定位置附加一行或多行,添加的数据为换行符。换行符被编码为$'\n',即作为“C 字符串”,这意味着我们正在使用理解这些的外壳(如bashzsh)。否则必须将其添加为文字换行符:

sed -s -e '$a\
' ./*.txt >concat.out
Run Code Online (Sandbox Code Playgroud)

实际上,'$a\\'并且'$a\ '似乎也有效,但我不完全确定为什么。

这也有效,如果有人认为a命令太麻烦而无法正确执行:

sed -s -e '${p;g;}' ./*.txt >concat.out
Run Code Online (Sandbox Code Playgroud)

这些变体中的任何一个也会在最后一个文件的输出末尾插入一个空行。如果不需要最后的换行符,请sed '$d'在重定向到输出文件之前通过传递整体结果来删除它:

sed -s -e '${p;g;}' ./*.txt | sed -e '$d' >concat.out
Run Code Online (Sandbox Code Playgroud)


αғs*_*нιη 5

使用 GNU awk

gawk -v RS='^$' -v ORS= '{
    print sep $0; sep="\n";
}' ./file*.txt >single.file
Run Code Online (Sandbox Code Playgroud)

看到awk 中的 Slurp 模式吗?

文件名中的前缀点斜杠./用于避免命名的文件出现问题,file=x.txt例如,当awk这些字符串出现在代码后面时,将这些字符串读取为变量;awk

另一种 GNUawk方法是:

gawk 'BEGINFILE{if (ARGIND>1) print ""};1' ./file*.txt >single.txt
Run Code Online (Sandbox Code Playgroud)

这是更好的,因为即使最后一行不以换行符结尾,它也会添加一个空行,并且可以避免将整个文件加载到内存中。


还有一种sed替代方法,但要删除最后一条\newline,您应该添加另一个管道sed ... | 来删除它。

sed -s '$s/$/\n/' file*.txt >single.file
Run Code Online (Sandbox Code Playgroud)


Sté*_*las 5

zsh有一个Pglob 限定符来为每个文件名加上任意参数的 glob 前缀。

虽然它通常用于为cmd *.txt(P[-i])每个文件名添加给定选项的前缀,但您可以使用此处在每个文件之前插入任何给定文件。可以使用 完成包含空行的临时文件=(print),因此您可以执行以下操作:

() { cat file*.txt(P[$1]); } =(print)
Run Code Online (Sandbox Code Playgroud)

在 Linux 或 Cygwin 上,您还可以执行以下操作:

cat file*.txt(P[/dev/stdin]) <<< ''
Run Code Online (Sandbox Code Playgroud)


JoL*_*JoL 5

也许不完全是您想要的,但就像评论中建议的 Quas\xc3\xadmodo 一样,tail除了带有文件名的标头之外,GNU 还可以添加空行:

\n
$ echo 'this is foo' > foo.txt \n$ echo 'this is bar' > bar.txt   \n$ tail -n+1 foo.txt bar.txt \n==> foo.txt <==\nthis is foo\n\n==> bar.txt <==\nthis is bar\n
Run Code Online (Sandbox Code Playgroud)\n

导致-n+1它打印整个文件;它的意思是“从第一行开始打印尾部”。

\n

如果您希望即使只有一个文件也添加标头以保持一致性,您可以使用-v.

\n
$ tail -n+1 foo.txt        \nthis is foo\n$ tail -v -n+1 foo.txt \n==> foo.txt <==\nthis is foo\n
Run Code Online (Sandbox Code Playgroud)\n