Shell中"cmd < file" 和 "cat file | cmd" 之间有什么区别
大多数情况下,这两个命令的作用是相同的,但第二个命令效率较低,并且在某些罕见情况下会出现问题。
假设 cmd 不是一个函数、内置命令或特殊的 shell 关键字,那么第一个命令 cmd < file 的工作原理如下:
- Shell 创建一个子shell。
- 在子shell中,关闭标准输入并使用文件以只读模式重新打开。
- 子shell 执行 cmd 命令,取代自身并读取文件内容。
- 父进程等待子shell 终止,然后继续正常执行。
第二个命令 cat file | cmd 的工作原理如下:
- Shell 创建两个子shell,并创建一个匿名管道。
- 管道连接两个子shell。
- 第一个子shell 执行带有文件参数的 cat 命令。cat 打开文件并将其内容复制到管道中。
- 第二个子shell 执行 cmd 命令,从管道中读取数据。
- 当两个子shell 都终止后,父进程继续正常执行。
因此,我们可以看出为什么第二个命令效率较低:它引入了额外的进程和匿名管道。
另一个区别是在第一个命令中,cmd 的标准输入是指向实际文件的文件描述符。命令可以回绕或以其他方式寻找文件中的不同位置。然而,在第二个命令中,cmd 的标准输入是一个匿名管道,而不是真正的文件。命令只能按顺序逐字节读取输入流,无法倒带、跳转到前后位置。
因此,期望可寻址标准输入的命令在使用第二个命令时可能会出现问题。这种情况很少见,但有时会发生。
在某些情况下,第二个命令也会较慢。如果 cmd 恰好是由 shell 实现的 while read 循环,那么 shell 将被迫使用单字节读取,而不是缓冲读取。
什么是 UUOC?
UUOC 是 "Useless Use Of Cat"(使用 cat 无用)的缩写。它是一个非正式术语,用于描述不正确的 "cat file | cmd" 结构。
在有经验的程序员圈子中,当一个新手做一些低效或错误的操作时,其他人通常会试图通过指出错误并展示正确的方法来帮助该人。在一些 Usenet 讨论组中,这成为了一种传统:新手会被“颁发”一个讽刺的 UUOC 奖项,一种成就的标志。
遗憾的是,有些人不欣赏他们所得到的帮助,将建设性的批评视为简单的批评。