Linux 中的 Cat 命令:基本和高级示例

继续浏览上周用 ls 命令开始的那些不太知名的命令,今天让我们来看看 cat 命令。

cat 名字代表 catenate 因为该命令的主要工作是通过在标准输出上按顺序发送内容来连接多个输入文件:

# 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 实用程序也经常只使用一个参数来将该文件的内容显示到屏幕上,就像我在最后一行所做的一样 example 多于。

A. 使用标准输入的 cat 命令

当不带任何参数使用时, cat command 将从其标准输入读取数据并将其写入其标准输出——这几乎是无用的……除非您使用某些选项来转换数据。 稍后我们将讨论几个有趣的选项。

除了文件路径, 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 的打开前半部分并查看它是否“损坏” display, 或者 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 档案

作为最后一个 example,让我们看看如何使用 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 标准命令,我们有一个简单的方法来删除它:

# 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. 基本 cat 命令选项

在玩过各种二进制文件格式之后,现在让我们通过研究几个专门为处理这些文件而定制的选项,回到普通的旧文本文件。 虽然不是 POSIX 标准的一部分,但这些选项可以跨 BSD 和 GNU 移植 cat 实施。 请注意,我并没有假装在这里面面俱到,所以请查看 man 查看支持的选项的完整列表 cat 在你的系统上!

-n: 数行

随着 n 选项, cat 命令将在每个输出行前加上行号:

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
[email protected]:~$ 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;

在里面 example 上面,您可以看到,在默认输出中,第 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

这 example 上面使用了两个实例 cat 管道中具有不同选项的命令。 内部编号来自 -b 与第一个一起使用的选项 cat 命令。 外部编号来自 -n 与第二个一起使用的选项 cat.

如您所见,第一行和最后一行没有由 -b 选项,因为它们是空的。 但是第 6 行呢? 为什么它仍然被编号 -b 选项? 好吧,因为它是一个空行——但不是空行,我们将在下一节中看到。

-v, -e, -t: 显示非打印字符

三个选项 -v, -e `, and `-t 用于显示不同的不可见字符集。 即使集合重叠,也没有“包罗万象”选项,因此如果要显示所有不可见字符,则必须将它们组合起来。

-v: 查看不可见字符

-v 选项显示所有非打印字符 插入符号 和元表示法,换行和制表除外。

使用该选项,控制字符将显示为插入符号 (^) 后跟适当的 ASCII 字符(例如, 回车,字节 13,显示为 ^M 因为 M 在 ASCII 中是 64 + 13),并且设置了高位的字符将以“元”表示法出现 M- 后跟对应于 7 个低位的表示(例如,字节 141 将显示为 M-^M 因为 141 是 128 + 13)。

虽然看似深奥,但该功能在处理二进制文件时可能很有用,例如 example,如果您想检查嵌入在 JPEG 文件中的原始信息:

$ cat -v cat.jpg | fold -75 | head -10
M-^?M-XM-^?M-`^@^PJFIF^@^A^A^A^@H^@H^@^@M-^?M-~^@QFile source: https://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^@^@^[email protected]^@^@
^@^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 分数? 它们用于替换原本不可见的回车符。 它从哪里来的? 那么, dict 协议,与任何其他 Internet 协议一样,正在使用 CRLF 作为行终止符。 因此,我们将它们作为示例文件的一部分下载。 您可以在 foldfmt 文章。 但是现在,它解释了为什么 cat 认为第 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 的字节,并且 I 在 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 command 被称为“无用”,因为一个简单的重定向或文件名参数就可以完成这项工作,并且做得更好。 但是一个 example 值一千字:

$ 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
[...]

在里面 example 上面,我使用了一个管道来显示 uuoc.txt 文件与 less 寻呼机:

cat uuoc.txt | less

所以,唯一的目的 cat 命令是提供标准输入 less 命令的内容 uuoc.txt 文件。 我会使用 shell 重定向获得相同的行为:

less < uuoc.txt

事实上, less 命令与许多命令一样,也接受文件名作为参数。 所以我可以简单地写成这样:

less uuoc.txt

如您所见,不需要 cat 这里。 如果我提到“无用使用 Cat”反模式,这是因为,如果你在论坛或其他地方公开使用它,毫无疑问会有人指出你将创建一个“无用的额外过程”。 ”

我必须承认很长一段时间我对这样的评论很不屑一顾。 毕竟,在我们的现代硬件上,为一次性操作生成一个额外的进程不会导致那么多开销。

但是在写这篇文章的时候,我做了一个 快速实验,通过测试比较使用和不使用 UUOC 所需的时间 awk 用于处理来自慢速媒体的 500MB 数据的脚本。

令我惊讶的是,差异远非微不足道:

但是,原因不在于创建了额外的进程。 但是由于额外的读/写和上下文切换,UUOC 会产生(正如您可以从执行系统代码所花费的时间推断出来的那样)。 确实如此,当您处理额外的大型数据集时 cat 命令的成本不可忽略。 至于我自己,我现在会努力提高警惕! 和你? 如果您有 Cat 无用使用的示例,请不要犹豫与我们分享!