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

标签 bash

我设法在我正在处理的初始化脚本中跟踪完成了一个奇怪的问题。我在以下示例中简化了问题:

> 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 不会提供这个

最佳答案

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

$cmd

只有一层膨胀发生。 $cmd 包含 echo "hello this is a test",扩展为 6 个空格分隔的标记:

  1. 回显
  2. “你好
  3. 这个
  4. 一个
  5. 测试”

这就是 set -x 输出向您展示的内容:它在包含双引号的标记周围加上单引号,以便清楚各个标记是什么。

如果您希望将 $cmd 扩展为一个字符串,然后再次应用所有 bash 引用规则,请尝试执行您的命令:

bash -c "$cmd"

或者(正如@bitmask 在评论中指出的那样,这可能更有效)

eval "$cmd"

不仅仅是

$cmd

关于Bash在执行前将引号插入字符串,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/6087494/

相关文章:

linux - 将某些列中包含多个分隔条目的文件拆分为单独的行

linux - Bash - 变量不在其他变量中计算

bash - sed 只匹配第一个表达式

Bash:如果存在,如何复制目录的文件

linux - 使用 tee 命令打印垃圾字符

bash - 如何在bash命令行获取Maven项目版本

linux - 如何在Linux中更改csv文件中的时间戳格式

linux - 如何使用 set 更改 shell 变量?

linux - 每次监视执行时的不同文件间接

bash - 如何获取具有特定列值的 csv 文件的前 n 行?