将文件内容输出到stdout的命令?


28

我知道cat可以做到这一点,但是它的主要目的是连接而不只是显示内容。

我也知道lessmore,但是我正在寻找一种简单的方法(不是分页器),该方法只是将文件的内容输出到终端,如果有的话,它就是为此专门制作的。


1
实际上,使用cat的99%的时间是显示文件而不是连接任何内容。
LatinSuD 2014年

1
@LatinSuD-100%的时间- cat连接。
mikeserv 2014年

@mikeserv:这与您执行操作的含义有关;正常的语言用法是指至少完成一次。“打印”一个空字符串不涉及打印任何字符。可以公平地说,它没有打印任何内容。现在,计算a+b+c涉及执行2个加法,而计算a不涉及任何加法。类似地,执行cat f不涉及串联任何内容(即使这是“串联一个文件的序列”的唯一含义)。
Marc van Leeuwen 2014年

2
@mikeserv:我不能理解您的意思。当然可以cat读取文件并写入另一个文件(流),但这并不意味着它可以串联任何内容。您可能应该说这cat f实际上是在做cat - f,但这不是真的。
Marc van Leeuwen 2014年

1
@ confused00:cat确实是要串联的(cat file1 file2将两个文件都串联到stdout)。但这是副作用,当只有1个文件作为参数时,它将把该文件输出到stdout(无论到哪里,无论是终端还是重定向到某个文件)。因此,没有其他命令可以仅在stdout上输出,就像cat已经存在并允许它一样。因此您要使用cat
奥利维尔·杜拉克

Answers:


37

最明显的是cat。但是,也可以看看headtail。还有一些其他的壳utillities打印的文件里逐行:sedawkgrep。但是这些是替换文件内容或在文件内部搜索。

我进行了一些测试,以评估哪种方法最有效。我全力以赴strace,看看哪个系统调用最少。我的文件有1275行。

  • awk:1355系统调用
  • cat:51个系统调用
  • grep:1337系统调用
  • head:93个系统调用
  • tail:130个系统调用
  • sed:1378系统调用

如您所见,即使cat设计用来连接文件,它也是最快,最有效的文件。sedawkgrep逐行打印文件,这就是为什么他们要进行1275多次系统调用的原因。


8
计算syscall的好主意!
2014年

1
+1,答案更准确(关于猫的意思),更完整(替代)和研究(系统调用)
Olivier Dulac

23

我知道cat可以做到这一点,但是它的主要目的是连接而不只是显示内容。

的目的cat恰恰是读取文件并将其输出到stdout。


1
但是cat --help说“将文件或标准输入连接到标准输出”。我不想连接任何内容
confused00

18
信不信由你,cat正是您要找的东西。
2014年

5
不,@ confused00,Jan的权利。问题是-终端 stdout-看到了吗?做readlink /dev/fd/1例如-你应该在那里得到你的tty的名称,如果在一个标准的提示符下运行。因此,将输入连接到输出就是您要执行的操作。
mikeserv 2014年

2
@mikeserv是的,我明白你的意思,我想我对“连接”的含义太固定了。
confused00

3
逻辑是,打印一个文件的内容只是按顺序打印一个或多个文件的内容的一种特殊情况。
zwol 2014年

10

首先,cat写入标准输出,它不一定是终端,即使它cat是作为交互式shell命令的一部分而键入的。如果即使重定向了标准输出,实际上仍然需要向终端写入内容,那么就不那么容易了(您需要指定哪个终端,如果从脚本执行命令,甚至可能没有一个)。如果命令仅仅是管道的一部分,则可能会(使用)标准错误输出。但是,既然您指出cat实际上可以完成工作,那么我想您不是在问这种情况。

如果您的目的是将写入标准输出的内容发送到管道中,则使用cat有资格获得“ 无用使用奖”,因为cat file | pipeline(其中pipeline代表任何管道)可以更高效地完成<file pipeline。但是,根据您的措辞,我再次得出结论,这不是您的意图。

因此,不清楚您在担心什么。如果cat键入时间太长,可以定义一个或两个字符的别名(在标准Unix中仍然有一些这样的名称未使用)。但是,如果您担心cat浪费无用的周期,则不应该这样做。

如果有一个null不带参数的程序,而只是将标准输入复制到标准输出(管道的中性对象),则可以使用进行所需的操作<file null。没有这样的程序,尽管编写起来很容易(只有一行main代码的C程序可以完成这项工作),但是cat不带参数的调用(或者cat -如果您想明确的话)就可以做到。

如果有一个nocat程序仅使用一个文件名参数,然后尝试打开文件,如果不能,则抱怨它,然后继续从文件复制到标准输出,这就是您所要的。编写它的工作仅比null打开文件,测试和可能抱怨(,如果您是一丝不苟的,您可能还想包括一个确实有一个论点的测试,否则抱怨)的主要工作要难一些。但是cat,现在再次提供了一个参数,就可以做到这一点,因此不需要任何nocat程序。

一旦成功编写了nocat程序,为什么只停一个参数呢?将代码包装成一个循环for(;*argp!=NULL;++argp)实际上一点也不费力,在二进制文件中最多添加了两条机器指令,并且避免了抱怨错误的参数数量(这省去了更多的指令)。Voilà的原始版本cat,串联文件。(说实话,您需要对其进行一些调整,以便在没有参数的情况下其行为都与一样null。)

当然,在实际cat程序中,他们会添加一些麻烦,因为它们总是这样做。但是本质是,“连接”方面的cat成本实际上根本没有花费,对于程序员和执行它的机器都没有。cat包含nullnocat解释了此类程序不存在的事实。cat如果结果进入管道,请避免使用单个参数,但如果仅将其用于在终端上显示文件内容,即使我链接到的页面也承认这是对有用的用法cat,所以请不要犹豫。


您可以cat通过假想nocat功能的简单循环来测试它的真实实现,方法是cat使用多个文件名进行调用,其中一个无效名称不在第一个位置:而不是立即抱怨该文件不存在,而是cat先转储以下文件有效文件,然后抱怨无效文件(至少这是我的猫的行为)。


7

zsh尝试下

<file

我相信这是打印文件的最短方法。它使用“隐藏” cat(或more如果stdout是终端),但是用于打印的命令由READNULLCMD变量控制,您可以安全地直接用命令名或某些功能覆盖该变量。例如,打印带有行号的文件:

numcat() { nl -s'> ' -w2 - }
READNULLCMD=numcat
<file

5

POSIX将cat定义为:

名称

cat-连接并打印文件

概要

猫[-u] [文件...]

描述

cat实用程序应按顺序读取文件,并应按相同顺序将其内容写入标准输出。

因此,我认为此处的串联意味着按顺序读取文件


5

我知道这是一个过去式的问题。从技术上讲,由于将文件内容打印到stdout是串联形式,cat因此从语义上讲是适当的。别忘了这printf在语义上意在格式化和打印数据。Bash还提供语法来重定向文件的输入和输出。这些的组合可能会产生以下结果:

printf '%s' "$(<file.txt)"

4
除了特别是回旋处外,显示的命令不等于cat file.txt,因为它会删除所有尾随的换行符(这样$(...)做)。
Marc van Leeuwen 2014年

+1,不错。不知道。
James M. Lay 2014年

3

使用bash内置函数并避免创建子流程:

{ while IFS='' read -rd '' _bcat_; do printf '%s\0' "${_bcat_}"; done; printf '%s' "${_bcat_}"; unset _bcat_; } <'/path/to/file'

IFS将仅应用于read命令,因此不必担心您的全局IFS更改。

需要循环来处理空字符(感谢StéphaneChazelas)。

这种方法不适用于大文件,因为文件内容首先读取到变量(即内存)。顺便说一句,我试图以此方式打印39M文本文件,并且bash内存使用量不超过5M,所以不确定这种情况。

它还令人讨厌,而且CPU效率低下:对于相同的39M文件,单核使用率为100%,耗时约3分钟。

对于大文件或二进制文件,最好使用它cat '/path/to/file',甚至dd if='/path/to/file' bs=1M可能的话。


1
另请参阅pv -q在Linux上splice()哪些可以对某些类型的stdin / stdout使用,可以提高性能。
斯特凡Chazelas

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.