一尘不染

Bash在执行之前将引号插入字符串

linux

我设法在正在处理的init脚本中完成了一个奇怪的问题。在下面的示例中,我将问题简化了:

> set -x                           # <--- Make Bash show the commands it runs
> cmd="echo \"hello this is a test\""
+ cmd='echo "hello this is a test"'
> $cmd
+ echo '"hello' this is a 'test"'  # <--- Where have the single quotes come from?
"hello this is a test"

bash为什么要在执行的命令中插入那些多余的单引号?

在上面的示例中,多余的引号不会引起任何问题,但是它们确实让我头疼。

出于好奇,实际的问题代码为:

cmd="start-stop-daemon --start $DAEMON_OPTS \
    --quiet \
    --oknodo \
    --background \
    --make-pidfile \
    $* \
    --pidfile $CELERYD_PID_FILE
    --exec /bin/su -- -c \"$CELERYD $CELERYD_OPTS\" - $CELERYD_USER"

产生此结果:

start-stop-daemon --start --chdir /home/continuous/ci --quiet --oknodo --make-pidfile --pidfile /var/run/celeryd.pid --exec /bin/su -- -c '"/home/continuous/ci/manage.py' celeryd -f /var/log/celeryd.log -l 'INFO"' - continuous

因此:

/bin/su: invalid option -- 'f'

注意:我在su这里使用命令,因为我需要确保在运行celeryd之前已设置用户的virtualenv。--chuid不会提供这个


阅读 254

收藏
2020-06-03

共1个答案

一尘不染

因为当您尝试执行命令时

$cmd

仅发生一层扩展。 $cmdcontains echo "hello this is a test",它扩展为6个以空格分隔的标记:

  1. echo
  2. "hello
  3. this
  4. is
  5. a
  6. test"

这就是set -x输出显示的内容:它将单引号括在包含双引号的标记周围,以明确各个标记的含义。

如果要$cmd扩展为一个字符串,然后再次应用所有bash引用规则,请尝试使用以下命令执行命令:

bash -c "$cmd"

或(如@bitmask在注释中指出,这可能更有效)

eval "$cmd"

而不只是

$cmd
2020-06-03