命令替换是一个实现命令交互的方法。它将一个命令的输出作为参数传给另一个命令。命令替换最初出现在 1979 年 Unix 7Bourne shell[1] 中。这之后的所有 Unix shell 中都有它的存在。这一特性后来也被其他编程语言采用,包括 PerlPHPRubyPowershell 以及微软的 CMD.exe 中的 FOR 和 ( ) 命令。

语法和解析方式 编辑

Shell 通常用创建一个子进程的方式实现命令替换。该子进程运行第一个命令,并将它的标准输出通过管道返回给 shell ,shell 会读取得到的输出并以空格作为分隔来解析。在管道关闭或者子进程终止前,shell 会一直等待,因为它无法确定子进程是否完成了全部的输出。因此,shell 会等待第一个子进程运行结束,然后才创建第二个子进程并运行下一个命令。

这个 C shell 示例演示了如何利用 fgrep 搜索包含 malloc 的所有 C 文件,并使用 vi 对搜索到的文件进行编辑。这里的 ` ... ` 是原始风格的语法,即使用反引号作为分隔符。这一风格被所有常见的Unix shell支持。

#!/bin/csh
vi `fgrep -l malloc *.c`

存在对于语法和解析方式的不同观点和反对意见。 尽管命令替换的语法易于输入(这对交互式命令处理器来说很重要),但由于这种语法下的左右分隔符相同[2],因此在遇到嵌套使用时很难使用。Kornshell(ksh)[3] 借鉴了变量替换的语法风格,使用 $( ... ) 解决了这个问题。今天大多数的 Unix shell 和 Powershell 都支持这种语法。

#!/bin/sh
vi $(fgrep -l malloc *.c)

将输出按空格做分隔来解析的做法也遭到了批评。这种做法在早期的 Unix 系统上表现良好,因为它的文件名中不包含空格,但在现代的 WindowsLinux 系统中,由于文件名可能会包含空格[4],导致这样的解析方式无法正确工作。例如,在先前的两个示例中,如果通配符匹配到的文件名包含空格,该文件名将被拆分成两个单独的参数传给 shell ,这显然和预期不符。Hamilton C shell 通过双反引号符号 `` ... ``  解决了这个问题:它只在换行符处解析。[5] 这是一个使用 PowerShell 中的 () 运算符进行命令替换的示例:

$MyVariable = (ls)
echo $MyVariable

表达式替换 编辑

在相关的编程语言 Common Lisp 和 Scheme 中,可以使用反引号(或称为“准引号”)运算符标记的表达式来调用功能。类似地,在 ABC 编程语言中,可以在文本显示(字符串字面量)中使用反引号括起来的表达式。例如,ABC 语言中的命令 WRITE '2 + 2 = 2+2' 的输出结果为 2 + 2 = 4。

另见 编辑

参考资料 编辑

  1. ^ Dahdah, Howard. The A-Z of Programming Languages: Bourne shell, or sh, An in-depth interview with Steve Bourne, creator of the Bourne shell, or sh. Computerworld. 2009-03-05. (原始内容存档于2023-05-13). 
  2. ^ Jerry Peek, Tim O'Reilly & Mike Loukides. UNIX Power Tools. 1-56592-260-3. 1998-08-04 [2023-05-07]. (原始内容存档于2023-05-12). 
  3. ^ Robbins, Arnold. Learning the Korn shell. Learning the Korn Shell Second edition. Sebastopol, CA: O'Reilly. 2002: 127. ISBN 978-1-4493-7128-9. OCLC 54115790. 
  4. ^ Johnson, Chris F. A. 8. Pro Bash Programming: Scripting the Linux Shell. New York: Apress. 2009: 84. ISBN 978-1-4302-1998-9. OCLC 567139717. 
  5. ^ Hamilton Laboratories. Hamilton C shell User guide: I/O redirection: Command substitution. web.archive.org. 2014-12-19. (原始内容存档于2014-12-19).