我用不同的 shell 测试了几个脚本,结果有所不同。
# test 1
foo(){ echo $(al);}
alias al='echo 123'
foo
# test 2
alias al='echo 123'
foo(){ echo $(al);}
alias al='echo abc'
foo
# test 3
alias foo='echo $('
echo $(foo echo '123'))
# test 4
alias foo='echo $('
echo "$(foo echo '123'))"
# test 5
alias bar='echo 123)'
echo $(bar
bash 5.1.16(使用 --posix) | 昆山2020.0.0 | zsh 5.9 | 破折号 0.5.12 | 亚什 2.53 | |
---|---|---|---|---|---|
测试1 | 123 | 123 | 123 | 阿尔:未找到 | 没有这样的命令al |
测试2 | ABC | ABC | ABC | 123 | 123 |
测试3 | 意外的标记) |
) 意外 |
123 | 123 | 123 |
测试4 | 123 | 123 | 123 | 123 | 123 |
测试5 | 意外的文件结束符 | ( 无与伦比的 |
未找到命令:barecho | 123 | 123 |
所以基本上 bash 和 ksh 进行惰性别名替换,而 dash 和 yash 进行急切别名替换。 zsh 的行为有点难以解释,特别是在情况 5 中,当它尝试查找 command 时barecho
。
测试 4 是所有 shell 都同意的唯一情况。这很令人困惑,因为POSIX标准 2.2.3 双引号说:
带引号的字符串中也包含在“$(”和匹配的“)”之间的输入字符不应受到双引号的影响,而是应定义其输出替换“$(...)”的命令当单词扩展时。令牌识别中的令牌化规则(不包括别名替换中的别名替换)应递归应用以查找匹配的“)”。
该标准规定,当尝试在双引号内的命令替换中查找匹配的括号时,shell 不应采用别名替换。但所有 shell 都在双引号内使用别名替换,而有些 shell 如果没有双引号则不会。
问题是:某些 shell 在某些情况下是错误的,还是它们只是不同?即是否有一些规则说明在这种情况下正确的行为应该是什么?