我试图执行以下命令:
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将引用的字符串标记为这样,我该如何让它停止?
答案 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[@]}")