Iwi*_*ist 27 shell standard posix command
如果 shell 被要求执行一个已知会终止的可能无用(或部分无用)的命令,例如cat hugeregularfile.txt > /dev/null,它是否可以跳过该命令的执行(或执行更便宜的等价物,例如, touch -a hugeregularfile.txt)?
更一般地说,shell 是否类似于 C 编译器,因为它可以对源代码执行任何转换,只要外部可观察的行为就像抽象机器评估它一样?
编辑
Nota Bene:我最初提出的问题有一个标题,询问是否允许shell进行这些优化,而不是是否应该甚至是否存在可以执行这些优化的实现。我对理论比实践更感兴趣,尽管两者都是受欢迎的。
sca*_*cai 26
不,那是个坏主意。
cat hugeregularfile.txt > /dev/null并且touch -a hugeregularfile.txt不一样。cat将读取整个文件,即使您将输出重定向到/dev/null. 阅读整个文件可能正是您想要的。例如为了缓存它,以便以后的读取速度会明显加快。外壳无法知道您的意图。
同样,C 编译器永远不会优化读取文件,即使您不查看所读取的内容。
Ant*_*hon 20
不,因为/dev/null它只是一个名称,可以用于任何其他设备或文件,而不是“通常”是数据接收器。
因此,shell(或任何其他程序)根据名称不知道它正在写入的文件是否正在对数据进行“真实”操作。AFAIK也没有shell程序可以进行的系统调用,以确定例如文件描述符实际上没有做任何事情。
您与优化 C 程序中的代码的比较不起作用,因为 shell 没有 C 编译器对一段源代码的总体概述。shell/dev/null对优化您的示例的了解不够,更像是 C 编译器对它动态链接到的函数调用中的代码不够了解,因此无法进行调用。
Sté*_*las 15
它不会优化正在运行的命令(并且您已经收到了许多很好的答案,告诉您为什么不应该这样做),但在某些情况下它可能会优化分叉、管道/套接字对、读取。它可能进行的优化类型:
trap设置了某些s,否则脚本中的最后一个命令可以在 shell 的进程中执行。例如在 中sh -c ls,大多数 sh实现(bash、mksh、ksh、zsh、yash、 的某些版本ash)不会派生一个进程来运行ls。ksh93,在调用外部命令之前,命令替换不会创建管道或派生进程($(echo foo)例如将扩展为foo没有管道/套接字对或派生)。read某些 shell ( bash, AT&T ksh)的内置函数检测到 stdin 是可查找的,它们将不会进行单字节读取(在这种情况下,它们将进行大量读取并返回到它们要读取的内容的末尾)。当看到 时cat hugeregularfile.txt > /dev/null,不允许 shell 相信这个动作是无用的——cat它不是 shell 的一部分,在理论上和实践中都可以做任何事情。
例如,用户可能已将可执行文件重命名rm为cat,并且该行突然执行外部可观察行为,即删除文件。
用户可能已经编译了一个cat进入无限循环的版本,因此 shell 不能假设它如您所建议的那样“已知终止”。
有人可能已经安装了一个cat按预期工作的版本,但是如果它以足够的权限运行,安装 rootkit 会带来额外的副作用——同样,shell 应该适当地执行它。