【问题标题】:bash command substitution executed as a single command not parsed as shell statementbash 命令替换作为单个命令执行,不被解析为 shell 语句
【发布时间】:2021-08-27 04:58:34
【问题描述】:

似乎命令替换将第一个令牌作为命令,其余作为命令的参数, 不被解析为 shell 语句。但 bash 手册说:

Bash 通过在子 shell 中执行命令来执行扩展 环境

例子

$ c="echo 123 ; echo 124"
$ d=`$c`
$ echo $d
123 ; echo 124

为什么 d 是 13 ; echo 124 而不是 123 124

【问题讨论】:

  • 有很多问题——而且结局不会很好(或干净)。 命令替换 运行单个命令或管道,但不运行单独的命令。本质上,您正在尝试包含两个命令的c='echo "123"; echo "124"'。你可以做d=$(eval $c),结果123 124,但请记住eval与evil只有一个字符——避免它。我会重构你的两个 echo 语句以避免任何这种混乱。
  • @DavidC.Rankin 你不解释为什么命令作为单个命令执行,如果c="{ echo 123; echo 124 ; }" 然后命令替换将其视为 shell 语句
  • 不要将命令放在变量中。请改用函数。
  • 或者如果你真的想要CommandSub那么直接c=$(echo 123 ; echo 124); echo "$c"
  • @yuanjianpeng - 来自man 1 bash,有两种形式:$(command)和旧的`command`。在这两种情况下都不是$(command1; command2) 形式。 Bash 在子shell 中执行命令。它不执行命令然后去寻找另一个。在d=$($c) 中调用时,变量中的命令替换不会进行分词。正如 Jetchisel 指出的那样——您可以将命令替换为c=$(echo "123"; echo "124"),只是不能将内部部分存储在变量中并在后续命令替换中扩展。

标签: bash command-substitution


【解决方案1】:

这是因为在d=`$c` 中,命令不是echo 123 ; echo 124,而是$c。

这意味着 Bash 遵循所谓的简单命令 described in detail in POSIX 的评估步骤。

跳过不相关的部分,涉及的步骤是:

  1. 不是变量赋值或重定向的词应被扩展。如果扩展后仍有任何字段,则第一个字段应视为命令名称,其余字段是命令的参数。

所以$c按照规则展开:

应从头到尾执行波浪号扩展(请参阅波浪号扩展)、参数扩展(请参阅参数扩展)、命令替换(请参阅命令替换)和算术扩展(请参阅算术扩展)。参见令牌识别中的第 5 项。

$c变成echo 123 ; echo 124

除非 IFS 为空,否则应对步骤 1 生成的字段部分执行字段拆分(请参阅字段拆分)。

echo 123 ; echo 124变成echo、123、;、echo、124

如果有命令名,则按照命令搜索和执行中的描述继续执行。

echo 使用参数123、;、echo、124 调用,并将它们打印出来。

为了让它按你预期的方式工作,必须有一个步骤“在扩展之后,获取结果字符串并根据 shell 语法规则再次解析它”,但没有。

这也是好事,因为想象一下如果read -p "Name: " name; 会让你输入"; rm -rf /; " 并将echo "Hello $name" 变成echo "Hello "; rm -rf /; ""

【讨论】:

    猜你喜欢
    • 2020-11-06
    • 2014-01-11
    • 2011-10-30
    • 2015-05-18
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-10-04
    • 1970-01-01
    相关资源
    最近更新 更多