Bash在执行前将引号插入string

我已经设法跟踪我正在工作的初始化脚本中的一个奇怪的问题。 我在下面的例子中简化了这个问题:

> 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命令,因为我需要确保用户的virtualenv是在celeryd运行之前设置的。 --chuid不会提供这个

Solutions Collecting From Web of "Bash在执行前将引号插入string"

因为当你尝试执行你的命令

 $cmd 

只有一层扩展发生。 $cmd包含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