cat 命令的名称来源于单词catenate,此单词的意思是一个接一个地连接起来。cat 命令的用途是连接文件或标准输入并打印,这个命令常用来显示文件内容,或者将 几个文件连接起来显示,或者从标准输入读取内容并显示。
# Let’s obtain first some sample data files:
curl -so – dict://dict.org/’d:felidae:gcide’ | unexpand -a -t 3 |
sed -Ee ‘/^151/,/^[.]/!d;/^[.0-9]/s/.*//’ > felidae.txt
curl -so – dict://dict.org/’d:felis:gcide’ | unexpand -a -t 3 |
sed -Ee ‘/^151/,/^[.]/!d;/^[.0-9]/s/.*//’ > felis.txt
# Catenate files
cat felidae.txt felis.txt
如果要将该串联的结果存储在文件中,则必须使用shell重定向:
cat felidae.txt felis.txt > result.txt
cat result.txt
即使它的主要设计目标是连接文件,cat实用程序通常也只使用一个参数来将该文件的内容显示在屏幕上,就像我在上面示例的最后一行中所做的那样。
A.使用带有标准输入的cat命令
当没有任何参数使用时,cat命令将从其标准输入读取数据并将其写入其标准输出 – 这通常是无用的…除非您使用某些选项来转换数据。 我们稍后会讨论几个有趣的选项。
除了文件路径之外,cat命令还将 – 特殊文件名理解为标准输入的别名。 这样,您可以在命令行上给出的文件之间插入从标准输入读取的数据:
# Insert a separator between the two concatenated files
echo ‘—-‘ | cat felis.txt – felidae.txt
B.使用cat命令和二进制文件
1.加入拆分文件
cat命令不对文件内容做任何假设,因此它将很乐意使用二进制数据。 重新加入由split或csplit命令破坏的文件可能有用的东西。 或者像我们现在一样加入部分下载:
#
# A picture by Von.grzanka (CC-SA 3.0)
# Optimize bandwidth usage by breaking the download in two parts
# (on my system, I observe a 10% gain that way compared to a “full” download)
curl -s -r 0-50000
https://upload.wikimedia.org/wikipedia/commons/thumb/b/b6/Felis_catus-cat_on_snow.jpg/1024px-Felis_catus-cat_on_snow.jpg
-o first-half &
curl -s -r 50001-
https://upload.wikimedia.org/wikipedia/commons/thumb/b/b6/Felis_catus-cat_on_snow.jpg/1024px-Felis_catus-cat_on_snow.jpg
-o second-half &
wait
我们现在有两个一半的图像。 您可以使用ImageMagick的显示器或gimp或任何其他能够读取图像文件的软件打开前半部分并看到它“损坏”:
display first-half
# -or-
gimp first-half
# -or-
firefox first-half
如果你研究我使用的curl命令,你会看到这两个部分完全互补。 前半部分是从字节0到50000,后半部分是从字节50001到文件末尾。 它们之间不应该缺少数据。 所以我们只需要将两个部分组合在一起(按正确的顺序)以获取完整的文件:
cat first-half second-half > image.jpg
display image.jpg
2.使用可流式文件格式
您不仅可以使用cat命令“重新加入”分成几个部分的二进制文件,但在某些情况下,您还可以通过这种方式创建新文件。 对于像MPEG传输流视频文件(.TS文件)文件格式,这种方法效果特别好:
# Let’s make a still video file from our picture
ffmpeg -y -loop 1 -i cat.jpg -t 3
-c:v libx264 -vf scale=w=800:h=-1
still.ts
# Let’s make a fade-in from the same picture
ffmpeg -y -loop 1 -i cat.jpg -t 3
-c:v libx264 -vf scale=w=800:h=-1,fade=in:0:75
fadein.ts
# Let’s make a fade-out from the same picture
ffmpeg -y -loop 1 -i cat.jpg -t 3
-c:v libx264 -vf scale=w=800:h=-1,fade=out:0:75
fadeout.ts
我们现在可以使用cat命令组合所有这些传输流视频文件,在输出中获得完全有效的TS文件:
cat fadein.ts still.ts fadeout.ts > video.ts
mplayer video.ts
由于TS文件格式,您可以按照您想要的顺序组合这些文件,甚至可以在参数列表中多次使用相同的文件在输出视频中创建循环或重复。显然,如果我们使用动画图像,这会更有趣,但我会让你自己这样做:许多消费级设备记录TS文件,如果他们不记录,你仍然可以使用ffmpeg转换几乎任何视频文件到传输流文件。不要犹豫,使用评论部分分享您的作品!
3.破解cpio档案
作为最后一个示例,让我们看看如何使用cat命令组合几个cpio档案。但这一次,它不会那么简单,因为它需要一些关于cpio存档文件格式的知识。
cpio存档按顺序存储文件的元数据和内容,这使其适合与cat实用程序进行文件级连接。不幸的是,cpio存档还包含一个用于标记存档结尾的预告片:
# Create two genuine CPIO `bin` archive:
$ find felis.txt felidae.txt | cpio -o > part1.cpio
2 blocks
$ echo cat.jpg | cpio -o > part2.cpio
238 blocks
$ hexdump -C part1.cpio | tail -7
000002d0 2e 0d 0a 09 09 20 20 5b 57 6f 72 64 4e 65 74 20 |….. [WordNet |
000002e0 31 2e 35 5d 0d 0a 0a 00 c7 71 00 00 00 00 00 00 |1.5]…..q……|
000002f0 00 00 00 00 01 00 00 00 00 00 00 00 0b 00 00 00 |…………….|
00000300 00 00 54 52 41 49 4c 45 52 21 21 21 00 00 00 00 |..TRAILER!!!….|
00000310 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |…………….|
*
00000400
$ hexdump -C part2.cpio | tail -7
0001da40 46 96 ab f8 ad 11 23 90 32 79 ac 1f 8f ff d9 00 |F…..#.2y……|
0001da50 c7 71 00 00 00 00 00 00 00 00 00 00 01 00 00 00 |.q…………..|
0001da60 00 00 00 00 0b 00 00 00 00 00 54 52 41 49 4c 45 |……….TRAILE|
0001da70 52 21 21 21 00 00 00 00 00 00 00 00 00 00 00 00 |R!!!…………|
0001da80 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |…………….|
*
0001dc00
对于cpio二进制存档,好的新内容是预告片具有280字节的固定长度。 因此,使用head standard命令,我们可以轻松地将其删除:
# Each archive end with the 280-byte trailer.
# To catenate both archives, just remove the trailer
# at the end of the first part:
$ head -c-280 part1.cpio | cat – part2.cpio > cat.cpio
$ cpio -it < cat.cpio
felis.txt
felidae.txt
cat.jpg
239 blocks
C.必需的猫命令选项
在使用各种二进制文件格式之后,让我们通过研究专门为处理这些文件而定制的几个选项来回到普通的旧文本文件。 虽然不是POSIX标准的一部分,但这些选项可以在BSD和GNU cat实现中移植。 请注意我不会假装在这里详尽无遗,因此请检查该人以查看系统中cat支持的完整选项列表!
-n:数字行
cat -n felidae.txt
1
2 Felidae Felidae n.
3 a natural family of lithe-bodied round-headed fissiped
4 mammals, including the cats; wildcats; lions; leopards;
5 cheetahs; and saber-toothed tigers.
6
7 Syn: family {Felidae}.
8 [WordNet 1.5]
9
-n选项编号输出行。 这意味着从一个输入文件切换到下一个输入文件时,计数器不会被重置,如果您自己尝试以下命令,您将看到它:
cat -n feli*.txt
-s:抑制重复的空输出行
使用-s选项,cat命令将仅折叠多个连续的空行:
cat -n felis.txt felidae.txt | sed -n 8,13p
8 lynx ({Felis lynx}) is also called {Lynx lynx}.
9 [1913 Webster +PJC]
10
11
12 Felidae Felidae n.
13 a natural family of lithe-bodied round-headed fissiped
linuxidc@linuxidc:~$ cat -ns felis.txt felidae.txt | sed -n 8,13p
8 lynx ({Felis lynx}) is also called {Lynx lynx}.
9 [1913 Webster +PJC]
10
11 Felidae Felidae n.
12 a natural family of lithe-bodied round-headed fissiped
13 mammals, including the cats; wildcats; lions; leopards;
在上面的示例中,您可以看到,在默认输出中,第10行和第11行是空的。 添加-s选项时,第二个空行被丢弃。
-b:仅编号非空行
与前面两个选项有些相关,-b选项会对行进行编号,但忽略空行:
$ cat -b felidae.txt | cat -n
1
2 1 Felidae Felidae n.
3 2 a natural family of lithe-bodied round-headed fissiped
4 3 mammals, including the cats; wildcats; lions; leopards;
5 4 cheetahs; and saber-toothed tigers.
6 5
7 6 Syn: family {Felidae}.
8 7 [WordNet 1.5]
9
上面的示例使用cat命令的两个实例,其中包含管道中的不同选项。内部编号来自第一个cat命令使用的-b选项。外部编号来自第二只猫使用的-n选项。
如您所见,第一行和最后一行未使用-b选项编号,因为它们是空的。但是第6行怎么样?为什么它仍然使用-b选项进行编号?好吧,因为它是一个空白行 – 但不是空行,我们将在下一节中看到。
-v,-e,-t:显示非打印字符
三个选项-v,-e`和`-t用于显示不同的不可见字符集。即使集合重叠,也没有“全包”选项,因此如果要显示所有不可见字符,则必须将它们组合在一起。
-v:查看不可见的字符
-v选项显示除插入符号和制表符号以外的带插入符号和元符号的所有非打印字符。
使用该选项,控制字符将显示为插入符号(^),后跟相应的ASCII字符(例如,回车符,字节13,显示为^M,因为ASCII中的M为64 + 13),以及具有高字符的字符 – 阶位设置将以“元”符号M-出现,其后是对应于7个低位的表示(例如,字节141将显示为M-^M,因为141是128 + 13)。
虽然看似深奥,但在使用二进制文件时,该功能可能很有用,例如,如果要检查嵌入在JPEG文件中的原始信息:
$ cat -v cat.jpg | fold -75 | head -10
M-^?M-XM-^?M-`^@^PJFIF^@^A^A^A^@H^@H^@^@M-^?M-~^@QFile source: http://commo
ns.wikimedia.org/wiki/File:Felis_catus-cat_on_snow.jpgM-^?M-b^LXICC_PROFILE
^@^A^A^@^@^LHLino^B^P^@^@mntrRGB XYZ ^GM-N^@^B^@ ^@^F^@1^@^@acspMSFT
^@^@^@^@IEC sRGB^@^@^@^@^@^@^@^@^@^@^@^@^@^@M-vM-V^@^A^@^@^@^@M-S-HP ^@^@^
@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@
^@^@^@^@^@^@^@^Qcprt^@^@^AP^@^@^@3desc^@^@^AM-^D^@^@^@lwtpt^@^@^AM-p^@^@^@^
Tbkpt^@^@^B^D^@^@^@^TrXYZ^@^@^B^X^@^@^@^TgXYZ^@^@^B,^@^@^@^TbXYZ^@^@^B@^@^@
^@^Tdmnd^@^@^BT^@^@^@pdmdd^@^@^BM-D^@^@^@M-^Hvued^@^@^CL^@^@^@M-^Fview^@^@^
CM-T^@^@^@$lumi^@^@^CM-x^@^@^@^Tmeas^@^@^D^L^@^@^@$tech^@^@^D0^@^@^@^LrTRC^
@^@^D<^@^@^H^LgTRC^@^@^D<^@^@^H^LbTRC^@^@^D<^@^@^H^Ltext^@^@^@^@Copyright (
-v选项的另一个用例是查找可能泄漏到文本文件中的控制字符。 如果你还记得它,我们上面有一个奇怪的问题,-b选项编号为第6个输入行,而它看起来像是空的。 所以让我们调查一下:
$ cat -v felidae.txt
Felidae Felidae n.^M
a natural family of lithe-bodied round-headed fissiped^M
mammals, including the cats; wildcats; lions; leopards;^M
cheetahs; and saber-toothed tigers.^M
^M
Syn: family {Felidae}.^M
[WordNet 1.5]^M
啊啊! 你看到那些^M标记了吗? 它们用于替换否则不可见的回车符。 它从哪里来的? 好吧,与任何其他Internet协议一样,dict协议使用CRLF作为行终止符。 所以我们将它们作为示例文件的一部分下载。 您可以在fold和fmt文章中了解有关换行和回车的更多信息。 但就目前而言,它解释了为什么猫认为第6行不是空的。
-e:显示不可见的字符,包括行尾
-e选项的作用类似于-v选项,除了它还会在每个换行符之前添加一个美元符号($),从而明确显示行的结尾:
$ cat -e felidae.txt
$
Felidae Felidae n.^M$
a natural family of lithe-bodied round-headed fissiped^M$
mammals, including the cats; wildcats; lions; leopards;^M$
cheetahs; and saber-toothed tigers.^M$
^M$
Syn: family {Felidae}.^M$
[WordNet 1.5]^M$
$
-t:显示不可见的字符,包括选项卡
-t选项的工作方式与-v选项类似,不同之处在于它还会使用^ I条符号表示法显示制表符(制表符存储为保存值9的字节,而ASCII格式为64 + 9 = 73):
$ cat -t felidae.txt
Felidae Felidae n.^M
^Ia natural family of lithe-bodied round-headed fissiped^M
^Imammals, including the cats; wildcats; lions; leopards;^M
^Icheetahs; and saber-toothed tigers.^M
^M
^ISyn: family {Felidae}.^M
^I^I [WordNet 1.5]^M
-et:显示所有隐藏的字符
正如我已经简要提到的那样,如果要显示所有非打印字符,包括制表符和行尾标记,则需要同时使用-e和-t选项:
$ cat -et felidae.txt
$
Felidae Felidae n.^M$
^Ia natural family of lithe-bodied round-headed fissiped^M$
^Imammals, including the cats; wildcats; lions; leopards;^M$
^Icheetahs; and saber-toothed tigers.^M$
^M$
^ISyn: family {Felidae}.^M$
^I^I [WordNet 1.5]^M$
$
额外奖励:在Linux中无用的cat命令
如果没有提到“无用的Cat”反模式,那么关于cat命令的文章就不会完整。
当您将cat用于将文件内容发送到另一个命令的标准输入的唯一目的时,就会发生这种情况。 使用cat命令被称为“无用”,因为简单的重定向或文件名参数可以完成这项工作,并且可以做得更好。 但是一个值得千言万语的例子:
$ curl -so – dict://dict.org/’d:uuoc:jargon’ | sed -Ee ‘/^151/,/^[.]/!d;/^[.0-9]/s/.*//’ > uuoc.txt
$ cat uuoc.txt | less
UUOC
[from the comp.unix.shell group on Usenet] Stands for Useless Use of {cat};
the reference is to the Unix command cat(1), not the feline animal. As
received wisdom on comp.unix.shell observes, ?The purpose of cat is to
concatenate (or ?catenate?) files. If it’s only one file, concatenating it
with nothing at all is a waste of time, and costs you a process.?
Nevertheless one sees people doing
cat file | some_command and its args …
instead of the equivalent and cheaper
<file some_command and its args …
or (equivalently and more classically)
some_command and its args … <file
[…]
在上面的例子中,我使用一个管道来显示uuoc.txt文件的内容,并使用较少的分页器:
cat uuoc.txt | less
因此,cat命令的唯一目的是使用uuoc.txt文件的内容提供less命令的标准输入。 我会使用shell重定向获得相同的行为:
less < uuoc.txt
事实上,较少的命令与许多命令一样,也接受文件名作为参数。 所以我可以简单地写一下:
less uuoc.txt
如你所见,这里不需要cat。如果我提到“无用的cat”反模式,这是因为,如果你在一个论坛或其他地方公开使用它,毫无疑问有人会指出你的论点,你会创建一个“额外的过程,什么也没有。 ”
我必须承认,很长一段时间我对这些评论都很不屑一顾。毕竟,在我们的现代硬件上,为一次性操作产生一个额外的过程不会导致那么多开销。
但在撰写本文时,我做了一个快速实验,通过测试awk脚本比较UUOC和非UUOC所需的时间来处理来自慢速媒体的500MB数据。
令我惊讶的是,差异远非微不足道,使用cat命令将数据传输到awk将导致严重的性能损失
但是,原因不是要创建额外的进程。但是由于额外的读/写和上下文切换,UUOC会产生(因为你可以从执行系统代码的时间推断它)。实际上,当您处理大型数据集时,额外的cat命令具有不可忽视的成本。至于我自己,我现在会尽力保持警惕!你呢?如果你有无用cat的例子,请不要犹豫与我们分享!