是否允许外壳优化出无用的终止命令?


27

如果要求外壳程序执行已知终止的可能无用的(或部分无用的)命令(例如)cat hugeregularfile.txt > /dev/null,它可以跳过该命令的执行(或执行便宜的等效 命令touch -a hugeregularfile.txt)吗?

更笼统地说,shell是否类似于C编译器,只要可以在外部观察到的行为就如同抽象机对其进行了评估一样,就可以对源代码执行任何转换

编辑

Nota Bene:我最初提出的问题有一个标题,询问是否允许 shell 进行这些优化,而不是是否应该甚至可以执行这些优化的实现。我对理论比对实践更感兴趣,尽管都欢迎。


不,外壳不如现代编译器聪明。实际上,这很愚蠢。它不会优化任何无用的代码。
devnull 2014年

12
壳不应该猜测用户的意图是什么。用户可能会尝试使用该命令执行几乎所有操作,即使有可能,对其进行优化也会是错误的操作。
克里斯·

1
无论说文件是设备还是文件,都cat大有不同。Shell可以知道该文件是设备,但它不一定可靠。
2014年

3
@StephaneChazelas C编译器无需“征询某人的许可”即可优化其编译程序。C标准中有一个as-if规则,允许他们这样做。POSIX标准看起来已经标准化至少一个壳(pubs.opengroup.org/onlinepubs/009695399/utilities/...),以及众多的其他实用程序(pubs.opengroup.org/onlinepubs/009604499/utilities/wc.htmlwc, 例如)。但是,据我所知,POSIX在外壳优化方面不占优势。还是呢?
Iwillnotexist Idonotexist 2014年

2
优化可以通过快捷方式提高性能,而不会影响功能。只要功能得到保证,我就看不到POSIX对象。您建议的优化虽然会破坏猫的规格。POSIX规范中有一些特定的用词可以适应进行的优化类型ksh。就像他们没有说单独的过程,而是在子外壳环境中允许节省分叉的优化。
斯特凡Chazelas

Answers:


26

不,那不是一个好主意。

cat hugeregularfile.txt > /dev/nulltouch -a hugeregularfile.txt不一样。cat即使将输出重定向到,也会读取整个文件/dev/null。读取整个文件可能正是您想要的。例如,为了缓存它,以便以后的读取将明显更快。外壳不知道您的意图。

同样,即使您不看读的东西,C编译器也永远不会优化读取文件的过程。


2
@Iwillnotexist:每个有用的命令(可以说true和除外false)都有潜在的副作用,而副作用几乎总是调用该命令的重点。如果cat不解决停止问题,外壳程序将无法提前知道这些副作用(对于外部程序,例如)。因此,它正确地不尝试,并假设您的意思是您所说的。
2014年

5
@IwillnotexistIdonotexist不,shell无法看到所有即将发生的事情。它不知道cat。实际上,cat从格式化硬盘驱动器到下载Internet ,任何事情都可以做。
scai 2014年

5
“ Unix并非旨在阻止其用户执行愚蠢的事情,因为这也将阻止他们执行聪明的事情。” – Doug Gwyn
Agi Hammerthief 2014年

7
@cHao甚至truefalse设置$?
凯尔·斯特兰德

3
正如@scai上面所指出的,可执行文件并不像语言的关键字:cat/dev/null具有典型意义,但是他们没有保证的行为是那样。为了在不保证预期行为不变的情况下执行优化,只能允许该优化涉及在Shell本身内实现的构造,而不是在执行环境中发现的事物……无论其名称看起来多么直观。
andybuckley 2014年

20

不可以,因为/dev/null它只是一个名称,可以用于任何其他设备或文件,而不是“通常”的数据接收器。

因此,shell(或任何其他程序)基于名称不知道它正在写入的文件是否正在对数据进行“真实”处理。也没有AFAIK可以由Shell程序进行任何系统调用来确定文件描述符实际上没有执行任何操作。

您无法与在C程序中优化代码进行比较,因为外壳没有C编译器对源代码的总体了解。Shell不太了解如何/dev/null优化您的示例,更像C编译器不了解动态链接到的函数调用中的代码(不进行调用)。


4
事实证明,ksh93 /dev/null有时会被特殊对待。具有其标准输出定向到一个内置的/dev/null,例如echo foo >/dev/null,不会导致正在做的任何写操作/dev/null。如果它正在调用非内置命令(例如cat file >/dev/null),它并没有做任何特别的事情。
Mark Plotnick

事实上,cat也可能是其他事情。实际上还有其他。
Orion 2014年

3
其实/dev/null是极少数的一个标准化的路径,随着/dev/tty/dev/console/tmp/dev//
吉尔斯(Gilles)'“ SO-不要邪恶”

2
@MarkPlotnick实际上cat ksh93内置的(除非您放在/opt/ast/bin之前/bin(或任何cat可用的地方),否则不会启用$PATH)。是的,虽然cat file > /dev/null与内建确实read的内容file,它并没有把它写到/ dev / null的(尽管它打开,fstats它)。
斯特凡Chazelas

14

它不会优化正在运行的命令(并且您已经收到了很多很好的答案,告诉您为什么不应该这样做),但是在某些情况下,它可能会优化分叉,管道/套接字对,读取。它可能会进行的优化:

  • 对于大多数现代的shell,除非trap已设置某些s,否则脚本中的最后一个命令通常将在shell进程中执行。例如,在sh -c ls大多数 sh的实现(bashmkshkshzshyash,的某些版本ash)将不会创建一个进程来运行ls
  • 在中ksh93,在调用外部命令之前,命令替换将不会创建管道或分支进程($(echo foo)例如,将扩展为foo没有管道/套接字对或分支的情况)。
  • 如果read某些外壳程序(bash,AT&T ksh)的内置命令检测到stdin是可搜索的,则它们将不进行单字节读取(在这种情况下,它们将进行较大的读取并返回到它们打算读取的末尾)。

我喜欢这个答案,但尚不清楚这是否是原始原因,还是该信息是否取自某些参考文献(我想深入研究)
yoniLavi 2014年

3
@yoniYalovitsky,这是原始原因ksh93是Shell在优化方面处于领先地位,因为它的目标被视为与编程语言(如)相提并论perl。因此,您可以查看ksh文档,代码(祝您好运)和邮件列表以获取更多信息。
斯特凡Chazelas

1
@HenkLangeveld,是的,你可以验证与sh -c 'ps -p "$$"'它会给你ps,而不是sh那些sh实现,或使用strace /桁架/ TUSC ...
斯特凡Chazelas

1
ksh -c 'ps; ps'和bash -c'ps; ps' 之间的区别很有趣。Ksh93的优化程度更高。
Henk Langeveld 2014年

1
@HenkLangeveld,取决于ksh我们在这里讨论的实现方式。mksh表现像bash。这种行为主要是为了优化system("some command")。请注意,对于被信号终止的进程的退出状态(在某些shell中),这种优化会有副作用。ksh93曾经有一个错误,即使设置了陷阱,它也在进行优化。
斯特凡Chazelas

7

当看到时cat hugeregularfile.txt > /dev/null,shell不允许其认为该操作是无用的- cat并非Shell的一部分,并且在理论上和实践上都无能为力。

例如,用户可能已将可执行文件重命名rmcat,并且该行突然执行了外部可观察到的行为,即删除了文件。

用户可能已经编译了cat进入无限循环的版本,因此shell无法像您建议的那样假定它是“已知终止的”。

可能有人已经安装了可以正常运行的版本cat,但是如果rootkit能够以足够的特权运行,则安装rootkit会带来额外的副作用—同样,shell应该适当地执行它。


2
实际上,mksh实际上是V=$(cat file)通过使其成为内置函数来进行优化的。因此,shell可以对其进行优化,但不能其仅转换touch -a
史蒂夫·施内普

1
@SteveSchnepp,cat 一个内置的mksh,但内置的度假胜地,以系统的cat,如果传递的任何选项,这就是为什么GNU catmksh -c 'cat /dev/null --help'不会产生相同的结果bash -c 'cat /dev/null --help',但mksh -c 'cat --help /dev/null'不给你一样bash -c 'cat --help /dev/null'(如mksh猫内置解析选项POSIX方式,而GNU cat则以GNU方式解析它们)。
斯特凡Chazelas

在bash和ksh93中,V=$(cat file)可以使用进行优化V=$(< file)。即使没有内置功能,也可以加快处理速度cat
Henk Langeveld 2014年
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.