1

我正在尝试创建一个 shell 脚本,将多个命令连接到一个字符串,然后执行这些命令。

以下成功(创建“y”和“z”文件并打印 ls 输出):

$ /bin/touch /z && ls && /bin/touch /y

但以下失败(创建 'y' 和 'z' 文件,还有 '&&' 和 'ls' 文件

$ A="/bin/touch /z && ls && /bin/touch /y"
$ $A

似乎通过使用$A二进制执行该行将touch字符串的其余部分作为参数,并且&&运算符没有按预期执行。&&(我也尝试用;,||等进行切换,但得到了相同的结果)

我发现了eval $A诀窍,但我仍然很好奇为什么会发生这种情况。(并且可能想跳过评估​​的需要)

谢谢!

4

1 回答 1

2

从广义上讲,评估命令行有两个阶段:解析和扩展。


当你进入

/bin/touch /z && ls && /bin/touch /y

首先将字符串解析为由空格分隔的初步单词系列:

  • /bin/touch
  • /z
  • &&
  • ls
  • &&
  • /bin/touch
  • /y

此时,它将&&s 识别为分隔由以下单词组成的简单命令列表:

  1. /bin/touch,/z
  2. ls
  3. /bin/touch,/y

现在,它对每个单词应用一组扩展,以尝试生成更多单词。在这种情况下,没有什么可扩展的,并且再次检查每个简单命令以识别命令本身及其参数:

  1. 命令/bin/touch,参数/z
  2. 命令ls,无参数
  3. 命令/bin/touch,参数/y

在 的情况下$A,解析很简单:初步系列中只有一个单词$A。那个词接下来经历扩展;唯一相关的是参数扩展,它生成与第一个示例的解析步骤中标识的单词列表相同的单词列表。这里的区别是列表没有进一步扩展;现在不是识别命令名称及其参数的时候。

  1. 命令/bin/touch,带参数...

    1. /z
    2. &&
    3. ls
    4. &&
    5. /bin/touch
    6. /y

字符串实际上永远不是捆绑一组命令的正确方法。你想要做的是定义一个函数

a () {
  /bin/touch /z && ls && /bin/touch /y
}

然后将其用作普通命令:

$ a
/z
$ ls
/z
/y
于 2017-11-14T15:47:35.603 回答