Bash将带引号的字符串标记为空格作为单个单词

时间:2014-10-03 21:18:36

标签: bash

我试图执行以下命令:

mkdir 'my dir'
CMD="ls 'my dir'"
RESULT=$($CMD)

这导致:

ls: 'my: No such file or directory
ls: dir': No such file or directory

使用"设置-x"在第二个命令显示实际发出的命令是:

之前
++ ls ''\''my' 'dir'\'''

这显然是从我实际想做的事情中抽象出来的;这段代码本身并不适用于任何目的。但我的问题是为什么bash将引用的字符串标记为这样,我该如何让它停止?

3 个答案:

答案 0 :(得分:4)

(几乎)所有语言都区分代码和数据:

args="1, 2"
myfunc(args) != myfunc(1, 2)

bash也是如此。将单引号放在文字字符串中不会使bash解释它们。

存储程序名称和参数(也称为简单命令)的正确方法是使用数组:

cmd=(ls 'my dir')
result=$("${cmd[@]}")
除非你引用双引号,否则Bash会自动在空格上分割单词,这就是为什么你的例子有时会起作用的原因。这是令人惊讶且容易出错的,除非你有充分的理由不这样做,否则你应该总是双引号变量。

使用eval也可以让bash将字符串解释为完全是bash代码。这经常被推荐,但几乎总是错误的。

答案 1 :(得分:0)

要提供另一种方法(一种适用于POSIX系统的方法),xargs可以为您进行此分析,只要您可以保证参数列表足够短,就不会拆分为多个单独的命令:

CMD="ls 'my dir'"
printf '%s\n' "$CMD" | xargs sh -c '"$@"' sh

答案 2 :(得分:-1)

解决方案1:使用sh -c

mkdir 'my dir'
CMD="ls 'my dir'" # careful: your example was missing a '
RESULT=$(sh -c "$CMD")

解决方案2:将CMD声明为数组

mkdir 'my dir'
CMD=(ls 'my dir') # array with 2 elements
RESULT=$("${CMD[@]}")