这可能在许多常见问题解答中-而不是使用:

cat file | command


(这被称为猫的无用),正确的方法应该是:

command < file


第二种“正确”的方式-操作系统不必产生额外的进程。
尽管知道,我仍然出于两个原因继续使用无用的cat。
/>

更美观-当数据仅从左向右均匀移动时,我喜欢。而且,将cat替换为其他内容(gzcatecho,...),添加第二个文件或插入新的过滤器(pvmbuffergrep ...)更加容易。
我“觉得”这可能是在某些情况下更快。因为有2个过程,所以速度更快,第一个(cat)执行读取,第二个执行任何操作。它们可以并行运行,这意味着有时执行速度更快。

我的逻辑是否正确(出于第二个原因)?

评论

猫是身份管道。它仅将其输入流式传输到其输出。如果链中的第二个程序可以从传递给cat的同一个参数中获取输入(或者从标准输入(如果不传递任何参数)中获取输入),则cat绝对是无用的,只会导致分叉一个附加过程和一个附加过程。正在创建管道。

@FrédéricHamidi,当cat没有自变量或自变量为-时,这是一个身份管道。但是,当它具有多个非破折号文件名参数时,它不仅可以用作标识管道,而且可以满足实际用途。

不幸的是,以前流行的partmaps.org链接已死。内容现在位于Porkmail.org/era/unix/award.html

另请参阅:unix.stackexchange.com/q/511827/20336

我观察到,如果要显示向右的数据流(原因1),可以通过在命令之前放置文件重定向来实现,如

#1 楼

直到今天,当一些新秀试图将UUOC钉在我身上作为我的答案之一时,我才知道这个奖项。这是一个cat file.txt | grep foo | cut ... | cut ...。我给了他一个主意,只有在访问了链接之后,他才给我提到了奖项的由来和做法。进一步的搜索使我想到了这个问题。不幸的是,尽管有意识地进行了某种程度的思考,但没有一个答案包含了我的理由。

我并不是要对他做出防御。毕竟,在我年轻的时候,我会将命令编写为grep foo file.txt | cut ... | cut ...,因为每当您执行频繁的单个grep时,您都将学习file参数的位置,并且已经知道第一个是模式,而后一个是文件名称。

当我回答问题时,使用cat是一个有意识的选择,部分原因是因为“好味道”(用Linus Torvalds的话),但主要是由于功能的令人信服的原因。 。

后一个原因更为重要,因此我将首先介绍它。当我提供管道作为解决方案时,我希望它可以重用。很可能会在另一个管道的末尾添加一个管道或将其拼接成另一个管道。在那种情况下,使用grep的file参数可以提高可重用性,并且如果file参数存在,很可能会在没有错误消息的情况下以静默方式进行操作。即当您期望同时包含grep foo xyz | grep bar xyz | wcxyz的行数时,bar将为您提供foo中包含bar的行数。在使用之前必须在管道中更改命令的参数很容易出错。加上无声失败的可能性,这成为一种特别隐蔽的做法。仅仅是对诸如上述无声失败之类的事情的一种直观的潜意识原理,当需要教育的人说“但不是那只猫没用”时,您就无法想到这一点。

我也会尝试使我提到的以前的“好口味”原因变得自觉。这个原因与Unix的正交设计精神有关。 grep不是cutls不是grep。因此,至少grep foo file1 file2 file3与设计精神背道而驰。正交的方式是cat file1 file2 file3 | grep foo。现在,grep foo file1只是grep foo file1 file2 file3的特例,如果您对grep foo file1 file2 file3的对待不同,那么您至少会用尽整个时钟周期来避免无用的猫奖。

这导致我们进入关于cat是串联的,而cat file1 file2 file3是串联的,因此它适合cat,但是由于cat file1 | grep foocat中不是串联的,因此我们违反了cat file1 file2和全能Unix的精神。好吧,如果是这样的话,那么Unix将需要一个不同的命令来读取一个文件的输出并将其吐到stdout(而不是分页或者只是单纯地吐到stdout)。因此,您会遇到这样的情况,您说dog file1或说cat file1并认真记住避免dog file1 file2以避免获得奖励,同时也避免dog,因为希望cat的设计会在指定多个文件时引发错误。

希望在这一点上,您对Unix设计人员表示同情,因为他们没有包含将文件吐到stdout的单独命令,同时还为串联命名<edit>而不是给它起其他名字。 <删除了对<的错误注释,实际上,</edit>是一种高效的无复制功能,可将文件吐到stdout,您可以将其放置在管道的开头,因此Unix设计人员确实为此grep提供了一些专门的功能

下一个问题是为什么仅将文件吐出或将多个文件串联到stdout而不进行进一步处理的命令为什么很重要?原因之一是要避免让每个在标准输入上运行的Unix命令都知道如何解析至少一个命令行文件参数,并将其用作输入(如果存在)。第二个原因是避免用户必须记住:(a)文件名参数的位置; (b)避免如上所述的静默管道错误。

这使我们了解到为什么grep确实具有额外的逻辑。这样做的基本原理是使用户能够流畅使用频繁且独立运行的命令(而不是作为管道使用)。对于可用性的显着提高,这是正交性的略微折衷。并非所有命令都应采用这种方式设计,并且不经常使用的命令应完全避免文件参数的额外逻辑(请记住,额外的逻辑会导致不必要的脆弱性(错误的可能性))。例外是允许文件参数,例如ls。 (顺便说一下,请注意,grep有一个完全不同的原因,它不仅接受而且还需要文件参数)

最后,如果像ls这样的特殊命令(但不是如果在指定文件参数时也可以使用标准输入,则必须生成q4312079q)。

评论


请注意,当使用多个文件名调用grep时,它将在找到的行之前添加在其中找到文件的文件名(除非您关闭该行为)。它还可以报告各个文件中的行号。如果仅使用cat来喂grep,则会丢失文件名,并且行号在所有文件(而不是每个文件)上都是连续的。因此,有理由让grep本身处理cat无法处理的多个文件。单文件和零文件大小写只是grep一般多文件使用的特殊情况。

–乔纳森·莱弗勒(Jonathan Leffler)
13年5月18日在21:20

正如kojiro的回答所指出的那样,使用 output和输出。

–乔纳森·莱弗勒(Jonathan Leffler)
13年5月18日在21:29

我认为人们(包括我)扔掉UUoC石头的原因之一是首先进行教育。有时人们会处理数千兆字节的巨大文本文件,在这种情况下,最小化管道(UUoC,将连续的垃圾收集成一个,aso)至关重要,通常可以基于OP确实不知道可能会进行细微调整的问题来安全地假定它巨大的性能影响。我完全同意您关于脑循环的观点,这就是为什么即使在不需要时我也会定期使用猫。但重要的是要知道它是不需要的。

– AdrianFrühwirth
13年5月18日在23:09

敬请谅解;我绝不是说猫没用。并不是说猫是没有用的。只是特定的构造不需要使用cat。如果愿意,请注意它是UUoC(猫的无用使用),而不是UoUC(猫的无用使用)。在很多情况下,cat是正确使用的工具。当它是正确使用的工具时,我没有问题(实际上,在我的回答中提到了一个案例)。

–乔纳森·莱弗勒(Jonathan Leffler)
13年5月19日在1:02

@randomstring我听到了,但是我认为这确实取决于用例。当在命令行上使用时,根据数据的不同,管道中可能不会有多大麻烦,但是当用作编程环境时,绝对有必要实现这些对性能至关重要的事情。特别是在处理bash时,就性能而言,它就像一个矩形的轮子(无论如何与ksh相比。我在这里说的慢了10倍-没开玩笑)。在处理较大的脚本或巨大的循环时,您确实想优化分叉(而不仅限于此)。

– AdrianFrühwirth
13年5月19日在20:54



#2 楼

不!

首先,重定向在命令的何处都无关紧要。因此,如果您希望重定向到命令的左侧,就可以了:

< somefile command




command < somefile

相同
其次,当您使用管道时,会发生n + 1个进程和一个子外壳。它绝对是较慢的。在某些情况下,n可能为零(例如,当您重定向到内置的Shell时),因此通过使用cat,您完全不必添加新进程。

作为概括,每当您发现自己使用管道时,值得花费30秒的时间来查看是否可以消除它。 (但是,花费不超过30秒的时间是不值得的。)以下是一些不必要地频繁使用管道和流程的示例:

for word in $(cat somefile); … # for word in $(<somefile); … (or better yet, while read < somefile)

grep something | awk stuff; # awk '/something/ stuff' (similar for sed)

echo something | command; # command <<< something (although echo would be necessary for pure POSIX)


随时进行编辑以添加更多内容例子。

评论


好吧,速度提升不会太大。

–达卡龙
15年8月13日在13:13

从技术上讲,将“
–死灵法师
2015年10月6日在8:37

我用来决定STDIN重定向到哪里的经验法则是,要尽一切可能使模棱两可/令人惊讶的可能性最小化。教条式地说它先于死灵法师的问题,但是教条式地说它就可以做同样的事情。考虑:stdout = $(foo bar -exec baz
-马克G。
17-4-4在1:02



@necromancer,<“ cat” grep狗在这里更容易阅读。 (我通常是赞成空白的,但是这种特殊情况非常例外)。

–查尔斯·达菲(Charles Duffy)
17-4-5在20:41




#3 楼

我不同意UUOC奖过于自大的大多数情况,因为当教别人时,cat是任何命令或棘手的复杂命令管道的方便占位符,这些命令或命令管道会产生适合所讨论的问题或任务的输出。

在Stack Overflow,ServerFault,Unix&Linux等网站或任何SE网站上尤其如此。

如果有人特别询问优化问题,或者您是否想添加有关以下内容的更多信息然后,很好,谈论使用cat如何效率低下。但是不要嘲笑人们,因为他们选择在示例中追求简单和易于理解,而不是看着我如何酷我!复杂性。

总之,因为猫并不总是猫。

也因为大多数喜欢奖励UUOC的人都这样做是因为他们更关心炫耀关于他们如何“聪明”,而不是帮助或教导人们。实际上,他们证明自己可能只是另一个新手,他们发现了一个小棒可以击败同龄人。


Update

这里是另一个UUOC,我在https://unix.stackexchange.com/a/301194/7696上发布了答案:

sqlq() {
  local filter
  filter='cat'

  # very primitive, use getopts for real option handling.
  if [ "" == "--delete-blank-lines" ] ; then
    filter='grep -v "^$"'
    shift
  fi

  # each arg is piped into sqlplus as a separate command
  printf "%s\n" "$@" | sqlplus -S sss/eee@sid | $filter
}


UUOC学徒会说这是UUOC,因为它很容易可以将$filter缺省设置为空字符串,并使if语句执行filter='| grep -v "^$"'但IMO,通过不将管道字符嵌入$filter中,此“无用”的cat起到了非常有用的作用:自我记录$filter行上的printf这一事实不仅是sqlplus的另一个参数,它还是一个可选的用户可选的输出过滤器。

如果需要多个可选的输出过滤器,则选项处理只需将| whatever附加到$filter即可-管道中额外的一个cat不会伤害任何东西或造成任何明显的损失性能。

评论


顺便说一句-POSIX并没有在[]中指定==,并且并非所有实现都接受它。标准化运算符为=。

–查尔斯·达菲(Charles Duffy)
17-4-5在20:36



#4 楼

使用UUoC版本时,cat必须将文件读取到内存中,然后将其写到管道中,并且该命令必须从管道中读取数据,因此内核必须将整个文件复制3次,而在重定向情况下,内核仅需复制一次文件。做一次比做三遍更快。

使用:

cat "$@" | command


是完全不同的,不一定是无用的的cat。如果该命令是一个接受零个或多个文件名参数并依次处理它们的标准过滤器,它仍然没有用。考虑一下tr命令:这是一个忽略或拒绝文件名参数的纯过滤器。要向其提供多个文件,您必须使用如图所示的cat。 (当然,单独讨论了tr的设计不是很好;没有真正的理由不能将其设计为标准过滤器。)如果您希望命令将所有输入都视为一个命令,而不是多个单独的文件,即使该命令可以接受多个单独的文件:例如,wc就是这样的命令。

cat single-file情况是无条件的。

#5 楼

为保护猫:
是的,
   < input process > output 
   process < input > output 

效率更高,但是许多调用都没有性能问题,因此您不必在意
人体工程学的原因:
我们习惯于从左到右阅读,因此像
    cat infile | process1 | process2 > outfile

这样的命令很容易理解。
    process1 < infile | process2 > outfile

有跳过process1,然后从左到右阅读。这可以通过以下方法治愈:
    < infile process1 | process2 > outfile

以某种方式看起来,好像有一个指向左侧的箭头,什么都没有。更令人困惑且看起来像是引人注目的引述是:
    process1 > outfile < infile

生成脚本通常是一个反复的过程,
    cat file 
    cat file | process1
    cat file | process1 | process2 
    cat file | process1 | process2 > outfile

逐步看到进度,而
    < file 

甚至不起作用。简单的方法不易出错,使用cat即可轻松实现人机工程学命令分类。
另一个主题是,在使用计算机和将计算机用作程序员之前,大多数人都将>和<作为比较运算符使用了
将两个操作数与<和>进行比较是可逆的,这意味着
(a > b) == (b < a)

我记得我第一次使用<进行输入重定向,我担心
a.sh < file 

的含义与
file > a.sh

相同,并且以某种方式覆盖了我的a.sh脚本。也许这对许多初学者来说是一个问题。
稀有差异
wc -c journal.txt
15666 journal.txt
cat journal.txt | wc -c 
15666

后者可以直接用于计算。
factor $(cat journal.txt | wc -c)

当然<可以在这里使用同样,而不是文件参数:
< journal.txt wc -c 
15666
wc -c < journal.txt
15666
    

,但谁在乎-15k?
如果偶尔遇到问题,我肯定会改变我养猫的习惯。
何时使用非常大或很多文件,避免使用cat很好。对于大多数问题,猫的使用是正交的,没有话题,没有问题。
在每个第二个shell主题上开始对cat讨论的这些无用的无用的使用只会令人讨厌和无聊。处理性能问题时,请活出生命并等待自己的成名。

评论


+11111 ..作为当前接受的答案的作者,我强烈推荐这种令人愉快的补充。具体的例子阐明了我经常抽象和冗长的论点,而从作者对文件> a.sh的早期恐惧中获得的笑声值得阅读:)感谢分享!

–死灵法师
19年4月6日在6:13

在此调用cat文件中| wc -c,wc​​需要读取stdin直到EOF,才开始计数字节。但是在这个wc -c <文件中,它只是统计stdin,发现它是一个常规文件并打印st_size而不是读取任何输入。对于大文件,性能差异将清晰可见。

–oguz ismail
19年11月19日在22:51



#6 楼

另一个问题是管道可以静默屏蔽子外壳。对于此示例,我将cat替换为echo,但是存在相同的问题。

echo "foo" | while read line; do
    x=$line
done

echo "$x"


您可能希望x包含foo,但事实并非如此。您设置的x位于子外壳中,以执行while循环。启动管道的Shell中的x具有不相关的值,或者根本没有设置。
在bash4中,您可以配置一些shell选项,以便管道的最后一条命令在同一shell中执行作为启动管道的工具,但是您可以尝试使用此方法

echo "foo" | while read line; do
    x=$line
done | awk '...'


,并且x再次位于while的子外壳中。

评论


在严格的POSIX shell中,这可能是一个棘手的问题,因为这里没有字符串或进程替换来避免管道。即使在这种情况下,BashFAQ 24也提供了一些有用的解决方案。

– kojiro
2012年7月29日在16:06

在某些外壳中,图示的管道不会创建子外壳。例子包括Korn和Z。它们还支持进程替换以及此处的字符串。当然,它们并不是严格意义上的POSIX。 Bash 4具有shopt -s lastpipe以避免创建子外壳。

–已暂停,直至另行通知。
2012年7月29日在16:26

#7 楼

正如经常指出这一点和许多其他Shell编程反模式的人一样,我不得不迟来了。

Shell脚本非常是一种复制/粘贴语言。对于大多数编写shell脚本的人来说,他们并不是在学习该语言。这只是他们必须克服的障碍,才能继续以他们实际上有点熟悉的语言来做事情。

在这种情况下,我认为它具有破坏性,甚至可能破坏性传播各种shell脚本反模式。理想情况下,人们应该可以在Stack Overflow上找到的代码以最小的更改就可以复制/粘贴到他们的环境中,并且对它们的理解不够完整。

在网络上许多Shell脚本资源中,Stack Overflow在用户可以通过编辑网站上的问题和答案来帮助改善网站的质量。但是,代码编辑可能会出现问题,因为很容易进行代码作者不希望的更改。因此,我们倾向于留下评论以建议对代码进行更改。

UUCA和相关的反模式注释不仅适用于我们所评论的代码的作者,而且还适用于本文档。它们是一个警告,它可以帮助网站的读者了解他们在这里找到的代码中的问题。

我们不能希望实现在Stack Overflow上没有答案建议无用的情况。 s(或未加引号的变量或cat或其他各种各样的反模式灾难),但我们至少可以帮助教育要复制/粘贴此代码到其脚本的最内层紧密循环中的用户,该循环执行数百万次..

就技术原因而言,传统观念是我们应尽量减少外部流程的数量;在编写Shell脚本时,这仍然是很好的一般指导。

评论


同样,对于大型文件,通过cat进行管道传输会带来大量额外的上下文切换和内存带宽(以及cat的读取缓冲区和管道缓冲区中多余的数据副本会污染L3缓存)。尤其是在大型多核计算机(如许多主机设置)上,缓存/内存带宽是共享资源。

– Peter Cordes
18 Mar 25 '18在16:28


您自己的博客显示高吞吐量下降了50%,您甚至没有关注对总吞吐量的影响(如果您有让其他内核忙碌的东西)。如果可以解决,我可能会在x264或x265使用所有核心对视频进行编码的同时运行测试,并查看它会减慢视频编码的速度。与单独添加的开销猫相比,bzip2和gzip压缩都非常慢(否则机器处于空闲状态)。很难读取表格(数字中间的换行?)。 sys时间增加了很多,但是与用户还是实际相比仍然很小?

– Peter Cordes
19年1月5日,9:37

#8 楼

我经常在示例中使用cat file | myprogram。有时我被指控对猫的无用使用(http://porkmail.org/era/unix/award.html)。我不同意是由于以下原因:



很容易理解正在发生的事情。

在阅读UNIX命令时,您希望得到一个命令然后是参数,然后是重定向。可以将重定向放置在任何地方,但很少见-因此人们将很难阅读示例。我相信

cat foo | program1 -o option -b option | program2




program1 -o option -b option < foo | program2


更容易阅读如果您将重定向移动到开始位置,令人不习惯这种语法的人感到困惑:

< foo program1 -o option -b option | program2


,示例应该易于理解。


它是易于更改。

如果您知道该程序可以从cat读取,则通常可以假定它可以读取任何输出到STDOUT的程序的输出,因此可以根据自己的需要进行调整并获得可预测的结果。


如果STDIN不是文件,则强调程序不会失败。

假设program1 < foo可以正常工作是不安全的那么cat foo | program1也将起作用。但是,可以假设相反。如果STDIN是文件,则此程序可以工作,但是如果输入是管道,则该程序将失败,因为它使用了seek:

# works
< foo perl -e 'seek(STDIN,1,1) || die;print <STDIN>'

# fails
cat foo | perl -e 'seek(STDIN,1,1) || die;print <STDIN>'



性能成本

进行额外的cat会产生成本。为了让我大致了解一下如何运行一些测试来模拟基线(cat),低吞吐量(bzip2),中吞吐量(gzip)和高吞吐量(grep)。 >
测试是在低端系统(0.6 GHz)和普通笔记本电脑(2.2 GHz)上进行的。它们在每个系统上运行了10次,并且选择了最佳时机来模拟每次测试的最佳情况。 $ ISO是ubuntu-11.04-desktop-i386.iso。

#9 楼

我认为(传统方式)使用管道要快一些;在我的盒子上,我使用了strace命令来查看发生了什么:

没有管道:

toc@UnixServer:~$ strace wc -l < wrong_output.c
execve("/usr/bin/wc", ["wc", "-l"], [/* 18 vars */]) = 0
brk(0)                                  = 0x8b50000
access("/etc/ld.so.nohwcap", F_OK)      = -1 ENOENT (No such file or directory)
mmap2(NULL, 8192, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0xb77ad000
access("/etc/ld.so.preload", R_OK)      = -1 ENOENT (No such file or directory)
open("/etc/ld.so.cache", O_RDONLY)      = 3
fstat64(3, {st_mode=S_IFREG|0644, st_size=29107, ...}) = 0
mmap2(NULL, 29107, PROT_READ, MAP_PRIVATE, 3, 0) = 0xb77a5000
close(3)                                = 0
access("/etc/ld.so.nohwcap", F_OK)      = -1 ENOENT (No such file or directory)
open("/lib/i386-linux-gnu/libc.so.6", O_RDONLY) = 3
read(3, "7ELF
toc@UnixServer:~$ strace cat wrong_output.c | wc -l
execve("/bin/cat", ["cat", "wrong_output.c"], [/* 18 vars */]) = 0
brk(0)                                  = 0xa017000
access("/etc/ld.so.nohwcap", F_OK)      = -1 ENOENT (No such file or directory)
mmap2(NULL, 8192, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0xb774b000
access("/etc/ld.so.preload", R_OK)      = -1 ENOENT (No such file or directory)
open("/etc/ld.so.cache", O_RDONLY)      = 3
fstat64(3, {st_mode=S_IFREG|0644, st_size=29107, ...}) = 0
mmap2(NULL, 29107, PROT_READ, MAP_PRIVATE, 3, 0) = 0xb7743000
close(3)                                = 0
access("/etc/ld.so.nohwcap", F_OK)      = -1 ENOENT (No such file or directory)
open("/lib/i386-linux-gnu/libc.so.6", O_RDONLY) = 3
read(3, "7ELFq4312078qq4312078qq4312078qq4312078qq4312078qq4312078qq4312078qq4312078qq4312078qq4312078qq4312078qq4312078qq4312078qq4312078qp2q4312078q04q4312078qq4312078qq4312078q"..., 512) = 512
fstat64(3, {st_mode=S_IFREG|0755, st_size=1552584, ...}) = 0
mmap2(NULL, 1563160, PROT_READ|PROT_EXEC, MAP_PRIVATE|MAP_DENYWRITE, 3, 0) = 0xb75c5000
mmap2(0xb773d000, 12288, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED|MAP_DENYWRITE, 3, 0x178) = 0xb773d000
mmap2(0xb7740000, 10776, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED|MAP_ANONYMOUS, -1, 0) = 0xb7740000
close(3)                                = 0
mmap2(NULL, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0xb75c4000
set_thread_area({entry_number:-1 -> 6, base_addr:0xb75c48d0, limit:1048575, seg_32bit:1, contents:0, read_exec_only:0, limit_in_pages:1, seg_not_present:0, useable:1}) = 0
mprotect(0xb773d000, 8192, PROT_READ)   = 0
mprotect(0x8051000, 4096, PROT_READ)    = 0
mprotect(0xb776c000, 4096, PROT_READ)   = 0
munmap(0xb7743000, 29107)               = 0
brk(0)                                  = 0xa017000
brk(0xa038000)                          = 0xa038000
open("/usr/lib/locale/locale-archive", O_RDONLY|O_LARGEFILE) = 3
fstat64(3, {st_mode=S_IFREG|0644, st_size=5540198, ...}) = 0
mmap2(NULL, 2097152, PROT_READ, MAP_PRIVATE, 3, 0) = 0xb73c4000
mmap2(NULL, 1507328, PROT_READ, MAP_PRIVATE, 3, 0x2a8) = 0xb7254000
close(3)                                = 0
fstat64(1, {st_mode=S_IFIFO|0600, st_size=0, ...}) = 0
open("wrong_output.c", O_RDONLY|O_LARGEFILE) = 3
fstat64(3, {st_mode=S_IFREG|0664, st_size=180, ...}) = 0
read(3, "#include<stdio.h>\n\nint main(int "..., 32768) = 180
write(1, "#include<stdio.h>\n\nint main(int "..., 180) = 180
read(3, "", 32768)                      = 0
close(3)                                = 0
close(1)                                = 0
close(2)                                = 0
exit_group(0)                           = ?
13
q4312078qq4312078qq4312078qq4312078qq4312078qq4312078qq4312078qq4312078qq4312078qq4312078qq4312078qq4312078qq4312078qp2q4312078q04q4312078qq4312078qq4312078q"..., 512) = 512 fstat64(3, {st_mode=S_IFREG|0755, st_size=1552584, ...}) = 0 mmap2(NULL, 1563160, PROT_READ|PROT_EXEC, MAP_PRIVATE|MAP_DENYWRITE, 3, 0) = 0xb7627000 mmap2(0xb779f000, 12288, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED|MAP_DENYWRITE, 3, 0x178) = 0xb779f000 mmap2(0xb77a2000, 10776, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED|MAP_ANONYMOUS, -1, 0) = 0xb77a2000 close(3) = 0 mmap2(NULL, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0xb7626000 set_thread_area({entry_number:-1 -> 6, base_addr:0xb76268d0, limit:1048575, seg_32bit:1, contents:0, read_exec_only:0, limit_in_pages:1, seg_not_present:0, useable:1}) = 0 mprotect(0xb779f000, 8192, PROT_READ) = 0 mprotect(0x804f000, 4096, PROT_READ) = 0 mprotect(0xb77ce000, 4096, PROT_READ) = 0 munmap(0xb77a5000, 29107) = 0 brk(0) = 0x8b50000 brk(0x8b71000) = 0x8b71000 open("/usr/lib/locale/locale-archive", O_RDONLY|O_LARGEFILE) = 3 fstat64(3, {st_mode=S_IFREG|0644, st_size=5540198, ...}) = 0 mmap2(NULL, 2097152, PROT_READ, MAP_PRIVATE, 3, 0) = 0xb7426000 mmap2(NULL, 1507328, PROT_READ, MAP_PRIVATE, 3, 0x2a8) = 0xb72b6000 close(3) = 0 open("/usr/share/locale/locale.alias", O_RDONLY) = 3 fstat64(3, {st_mode=S_IFREG|0644, st_size=2570, ...}) = 0 mmap2(NULL, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0xb77ac000 read(3, "# Locale name alias data base.\n#"..., 4096) = 2570 read(3, "", 4096) = 0 close(3) = 0 munmap(0xb77ac000, 4096) = 0 open("/usr/share/locale/fr_FR.UTF-8/LC_MESSAGES/coreutils.mo", O_RDONLY) = -1 ENOENT (No such file or directory) open("/usr/share/locale/fr_FR.utf8/LC_MESSAGES/coreutils.mo", O_RDONLY) = -1 ENOENT (No such file or directory) open("/usr/share/locale/fr_FR/LC_MESSAGES/coreutils.mo", O_RDONLY) = -1 ENOENT (No such file or directory) open("/usr/share/locale/fr.UTF-8/LC_MESSAGES/coreutils.mo", O_RDONLY) = -1 ENOENT (No such file or directory) open("/usr/share/locale/fr.utf8/LC_MESSAGES/coreutils.mo", O_RDONLY) = -1 ENOENT (No such file or directory) open("/usr/share/locale/fr/LC_MESSAGES/coreutils.mo", O_RDONLY) = -1 ENOENT (No such file or directory) open("/usr/share/locale-langpack/fr_FR.UTF-8/LC_MESSAGES/coreutils.mo", O_RDONLY) = -1 ENOENT (No such file or directory) open("/usr/share/locale-langpack/fr_FR.utf8/LC_MESSAGES/coreutils.mo", O_RDONLY) = -1 ENOENT (No such file or directory) open("/usr/share/locale-langpack/fr_FR/LC_MESSAGES/coreutils.mo", O_RDONLY) = -1 ENOENT (No such file or directory) open("/usr/share/locale-langpack/fr.UTF-8/LC_MESSAGES/coreutils.mo", O_RDONLY) = -1 ENOENT (No such file or directory) open("/usr/share/locale-langpack/fr.utf8/LC_MESSAGES/coreutils.mo", O_RDONLY) = -1 ENOENT (No such file or directory) open("/usr/share/locale-langpack/fr/LC_MESSAGES/coreutils.mo", O_RDONLY) = 3 fstat64(3, {st_mode=S_IFREG|0644, st_size=316721, ...}) = 0 mmap2(NULL, 316721, PROT_READ, MAP_PRIVATE, 3, 0) = 0xb7268000 close(3) = 0 open("/usr/lib/i386-linux-gnu/gconv/gconv-modules.cache", O_RDONLY) = 3 fstat64(3, {st_mode=S_IFREG|0644, st_size=26064, ...}) = 0 mmap2(NULL, 26064, PROT_READ, MAP_SHARED, 3, 0) = 0xb7261000 close(3) = 0 read(0, "#include<stdio.h>\n\nint main(int "..., 16384) = 180 read(0, "", 16384) = 0 fstat64(1, {st_mode=S_IFCHR|0620, st_rdev=makedev(136, 2), ...}) = 0 mmap2(NULL, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0xb7260000 write(1, "13\n", 313 ) = 3 close(0) = 0 close(1) = 0 munmap(0xb7260000, 4096) = 0 close(2) = 0 exit_group(0) = ?


和管道:

q4312078q

可以使用带有更多和更长命令的stracetime命令进行一些测试,以实现良好的基准测试。

评论


我不明白您使用管道的(传统方式)是什么意思,或者您为什么认为此strace显示了它更快的速度–在第二种情况下,该strace没有跟踪wc -l执行。它仅在此处跟踪管道的第一个命令。

– kojiro
12年7月29日在22:55

@kojiro:我的意思是传统方式=最常用的方式(我认为我们使用管道多于间接方式),我无法确认它是否更快,在我的跟踪中,我看到了更多的间接方式系统调用。您可以使用一个c程序和一个循环来查看,这将花费更多时间。如果您有兴趣,我们可以放在这里:)

– TOC
2012年7月29日23:00

苹果对苹果的比较将把strace -f sh -c'wc -l <​​error_output.c'和strace -f sh -c'catrong_output.c |放在一起。 wc -l'。

–查尔斯·达菲(Charles Duffy)
17-4-5在20:39



以下是ideone.com的结果,目前显然不支持cat:ideone.com/2w1W42#stderr

–tripleee
17年12月11日12:06



@CharlesDuffy:mkfifo创建一个命名管道。使用pipe(2)设置一个匿名管道,然后进行分叉,并使父级和子级关闭管道的不同端。但是,是的,这个答案完全是胡说八道,甚至都没有尝试计算系统调用或使用strace -O来衡量开销,或者使用-r来将每个调用相对于上一个时间戳记...

– Peter Cordes
18-3-25在16:31