扩张和代换在 shell 编程语言的相同上下文中似乎可以互换。例如,一些文档,例如Bash 参考手册,Bash 黑客维基用“扩展”这个词来解释“shell参数”扩张'。然而,其他一些文件似乎更喜欢“替代”这个词。高级 Bash 脚本指南使用参数替代。
就 shell 编程术语而言,“扩展”和“替换”之间有什么区别吗?
答案1
代换几乎是同义词扩张在这种情况下,因为它们的含义重叠。两者都不是另一个的完整子类别,尽管在GNU手册您引用的部分中有一些替换被视为整体扩展的一部分。
一个扩张正在提取标识符的值。例如,如果this=that
,当我们展开时this
我们得到that
。不涉及替换的扩展是预先确定的,因为所使用的值已经存在并且必须简单地是检索到,尽管这包括组合检索/显式值(例如“算术扩展”)。
A代换创建一个值作为显式输入/输出操作的结果。例如, ifthis=$(foo bar)
是执行并捕获其输出this
的结果。 1虽然替换产生的值可能是完全可预测的,但它与正常扩展中检索到的值不同,因为在替换发生之前它实际上并不存在 - 它是foo bar
产生的。
替代品有两种口味,命令和过程,它们有点对称:
# Command substitution
foo=$(ls)
# Process substitution
wc <(ls)
第一个中的“命令”是ls
,第二个中的“进程”也是。我们可能会说被替换的实际上是管道的末端。流程替代重叠重定向。然而,这在技术上可能有点过于严格,这让我们看到脚注......
foo bar
在这种情况下可能是一个内部 shell 函数,在这种情况下它没有进程间 IO。 shell 内置函数的存在不太明显地掩盖了这种差异。就内容而言,输入和输出将是相同的。
答案2
set -- arg arg2
echo ${2+"$1"}
#OUTPUT
arg
shift
echo ${2+"$1"}
#OUTPUT
#there doesn't seem to be anything here
我认为这种差异一般来说太小了,不值得注意——而且这些术语经常可以互换使用。不过,如果你看一下上面的两个例子,你会发现在第一个例子中我们代替 $1
因为$2
由于扩张的$2
。一旦$2
不能扩大没有代换。
《金发姑娘》很好地阐述了替代品的虚无缥缈的存在。我猜有点像薛定谔的猫。这让我想起一件事。您可能不熟悉这种形式的 POSIX 指定的参数扩展,但它的工作方式与上述形式相反:
${var:?if $var is unset or null its \
parent shell dies and this message is output to stderr}
现在有时我想要相同的行为,但有一个set
值。 POSIX 没有明确指定任何事物的行为。但是,通过一两个技巧,它就可以轻松管理:
N= #N is null
var="any value should fail"
${var:+${N:?we substitute our \$Null var when \$var is expanded}}
#OUTPUT
sh: line 3: N: we substitute our $Null var when $var is expanded
但:
N= #N is null
var=
${var:+${N:?is never substituted}}
#OUTPUT
#there doesn't seem to be anything here