子 shell 中的 bash -c 给出 EOF 解析错误

子 shell 中的 bash -c 给出 EOF 解析错误

为什么以下脚本按预期工作(打印hello

#!/bin/bash

foo=$(bash -c 'echo hello')
echo $foo

而这个脚本:

#!/bin/bash

cmd="bash -c 'echo hello'"
foo=$($cmd)
echo $foo

给出以下错误:

hello': -c: line 0: unexpected EOF while looking for matching `''
hello': -c: line 1: syntax error: unexpected end of file

答案1

在,

cmd="bash -c 'echo hello'"
$cmd

您运行的不是bash -c 'echo hello'命令,而是$cmd简单的命令。

不加引号$cmd意味着调用 split+glob 运算符。这里,使用默认值$IFS, 的内容$cmd被拆分为bash-c'echohello'。因此,您正在bash使用这 4 个参数运行,就好像您输入了:

bash -c "'echo" "hello'"

'echo代码缺少结束引号(hello'参数进入$0该内联脚本的)。

$cmd如果你想评估shell 代码的内容,那就是

eval "$cmd"

所以:

cmd="bash -c 'echo hello'"
foo=$(eval "$cmd")
echo "$foo"

尽管您也可以以不同的方式使用 split+glob 运算符:

cmd='bash,-c,echo hello'
IFS=, # split on comma
set -f # disable glob
foo=$($cmd)
echo "$foo"

答案2

让我们看一下里面正在执行什么$($cmd)

$ cmd="bash -c 'echo hello'"
$ foo=$(printf '<%s>' $cmd)
$ echo "$foo"
<bash> <-c> <'echo> <hello'>

可以看到,执行的命令行是:

$ foo=$( "bash" "-c" "'echo" "hello'")

表达式的一侧有一个单引号:"'echo",它被解析为要执行的命令,并且它(正确地)报告缺少bash -c结束单引号。`''

一种解决方案是使用 eval 促进命令的正确解析:

$ foo=$(eval "printf '<%s>' $cmd"); echo "$foo"
<bash><-c><echo hello>

这有效:

$ foo=$(eval "$cmd"); echo "$foo"
hello

但正确的想法是:“变量存储数据,函数存储代码”

$ cmd(){ bash -c 'echo hello'; }
$ foo=$(cmd); echo "$foo"
hello

相关内容