在条件赋值中避免使用 subshel​​l

在条件赋值中避免使用 subshel​​l

我是 Linux shell 的初学者,但我知道这个命令会创建一个子 shell:

子 shell 通常是使用子 shell 运算符或命令(例如括号 ()、反引号 ` 或 $() 语法)创建的。

: ${FOO:=$([ "$BAR" = "baz" ] && echo "true" || echo "false" )}

这可能是一个问题,例如在循环中(这里的情况并非如此)但我喜欢学习如何避免它。一般来说,在上面的作业中,可以使用以下内容来避免子shell吗?

if [ -z "$FOO" ]; then
  if [ "$BAR" = "baz" ]; then
    FOO=true
  else
    FOO=false
  fi
fi

答案1

一般来说,在上面的分配中,是否可以使用以下内容来避免子shell?

if [ -z "$FOO" ]; then
  if [ "$BAR" = "baz" ]; then
    FOO=true
  else
    FOO=false
  fi
fi

是的,这才是正确的写法。

: ${FOO:=$([ "$BAR" = "baz" ] && echo "true" || echo "false" )}

运行子 shell(在大多数 shell 中涉及代价高昂的进程分叉),并且由于以下几个原因也是错误的:

  • ${FOO...}扩展未加引号,因此受到 split+glob 的影响,使其至少成为 DoS 漏洞(这是给出的示例之一)忘记在 bash/POSIX shell 中引用变量的安全隐患)。
  • echo "false"[如果或失败则运行,而您希望它仅在失败echo true时运行。不能适当替代.[a && b || cif a; then b; else c; fi

在 ksh93 shell 中,可以通过以下方式避免子 shell 和这些问题:

: "${FOO:=${
  if [ "$VAR" = baz ]; then
    echo true
  else
    echo false
  fi
}}"

但这与上面标准且明显的if陈述相比没有什么优势。

答案2

对于一个神秘的单行,我认为这将在没有子 shell 的情况下达到预期的结果:

[[ "$BAR" = "baz" ]] && FOO=${FOO-true} || FOO=${FOO-false}

但我会选择if....

相关内容