Linux Bash变量默认值不为';如果后面跟着管道(bash bug?)
我刚刚在Linux Bash变量默认值不为';如果后面跟着管道(bash bug?),linux,bash,Linux,Bash,我刚刚在bash中发现了一个我不理解的奇怪行为。表情 ${variable:=default} 将变量设置为默认值(如果尚未设置)。考虑下面的例子: #!/bin/bash file ${foo:=$1} echo "foo >$foo<" file ${bar:=$1} | cat echo "bar >$bar<" #/bin/bash 文件${foo:=$1} echo“foo>$foo$bar在第二种情况下,文件是一个管道成员,在其自己的外壳中作为每个管道成员
bash
中发现了一个我不理解的奇怪行为。表情
${variable:=default}
将变量
设置为默认值(如果尚未设置)。考虑下面的例子:
#!/bin/bash
file ${foo:=$1}
echo "foo >$foo<"
file ${bar:=$1} | cat
echo "bar >$bar<"
#/bin/bash
文件${foo:=$1}
echo“foo>$foo$bar在第二种情况下,文件
是一个管道成员,在其自己的外壳中作为每个管道成员运行。当文件
及其子外壳结束时,$b
及其来自$1
的新值不再存在
解决方法:
#!/bin/bash
file ${foo:=$1}
echo "foo >$foo<"
: "${bar:=$1}" # Parameter Expansion before subshell
file $bar | cat
echo "bar >$bar<"
!/bin/bash
文件${foo:=$1}
echo“foo>$foo$bar这不是一个bug。参数扩展发生在对命令进行求值而不是分析时,但在新进程启动之前,作为管道一部分的命令不会求值。改变这一点,除了可能破坏一些现有代码外,还需要在进行评估之前进行额外的扩展
假设的bash
会话:
> foo=5
> bar='$foo'
> echo "$bar"
$foo
# $bar expands to '$foo' before the subshell is created, but then `$foo` expands to 5
# during the "normal" round of parameter expansion.
> echo "$bar" | cat
5
为了避免这种情况,bash
需要某种方法来标记新的第一轮预评估参数扩展所产生的文本片段,这样它们就不会经历第二轮预评估
第二轮评估。这种记账方式会很快导致无法维护的代码,因为会发现有更多的角落案例需要处理。更简单的方法是接受参数扩展将被推迟到子shell启动之后
另一种选择是允许每个组件在当前shell中运行,这是POSIX标准允许的,但也不是必需的<代码>bash
很久以前就做出选择,在子shell中执行每个组件,而反过来会破坏太多依赖于当前行为的现有代码。(bash
4.2确实引入了lastpipe
选项,允许管道的最后一个组件在当前shell中执行(如果显式启用)。很可能是一个bug,您应该报告它。@ammoQ,没有类似的;记录的行为,甚至是常见问题的一部分。这是一个bash
功能,而不是bash
错误……这是否意味着参数扩展是在子shell中执行的,而不是在创建子shell之前执行的?@starfry:chepner在他的回答中正确地解释了这一点。在我的bash版本4.3.30中,echo“$bar”| cat
导致打印$foo
,而不是5
。是;我展示的示例是假设的,不代表bash的任何真实版本,以演示如果在当前shell中扩展参数,bash将需要做额外的工作来避免这种双重扩展。
> foo=5
> bar='$foo'
> echo "$bar"
$foo
# $bar expands to '$foo' before the subshell is created, but then `$foo` expands to 5
# during the "normal" round of parameter expansion.
> echo "$bar" | cat
5