我想做这样的事情。
$ touch a\ b
$ cmd=cat\ a\ b
$ echo $cmd
cat a b
$cmd
cat: a: No such file or directory
cat: b: No such file or directory
文件中的空格有问题a b
。所以我尝试了这个。
$ cmd=cat\ a\\\ b
$ echo $cmd
cat a\ b
$ $cmd
cat: a\': No such file or directory
cat: b: No such file or directory
这也失败了。我怎样才能让我跑步时$cmd
猫a b
?
答案1
set -- cat "a b"
"$@"
这将cat
使用单个参数运行a b
。的扩展"$@"
(包括双引号!)将是单独引用的位置参数的列表。位置参数通过 进行设置set
。
不过,将命令名称包含在列表本身中的情况并不常见。会比较常见
set -- "a b"
cat "$@"
或者,如果您想保留实际的命令名称变量,
cmd=cat
set -- "a b"
"$cmd" "$@"
如果您在设置文件名操作数和运行命令之间想要向命令添加更多文件名或选项,只需修改$@
:
cmd=cat
set -- "a b"
# later (adding more files to the end):
set -- "$@" "more files" "some glob here-"[0-9]
# later (adding an option at the front):
set -- -v "$@"
"$cmd" "$@"
$@
请注意,如果命令名称已经存在,则很难添加到前面。在这种情况下,您必须将shift
命令名称临时放入$@
一个单独的变量中,添加您想要添加的内容,然后再次添加命令名称:
cmd=$1
shift
set -- "$cmd" -v "$@"
我们通常想要使用set --
而不仅仅是set
设置位置参数。停止--
命令行选项解析器检测命令行参数列表中该点之后的命令行选项。请注意,如果没有--
,则不可能在with-v
前面添加字符串,就像完全不同的情况一样。$@
set
set -v
有关的:
答案2
当您使用echo $cmd
或$cmd
不加引号时,将对 的内容调用 split+glob $cmd
。这与当您echo cat a b
使用 shell 的语法解释将cat
,a
分隔b
成不同的参数传递给时发生的情况无关echo
。
split+glob 的分割部分是根据默认包含 SPC 的内容进行的$IFS
,因此分割后的单词永远不会包含 SPC。您需要使用不同的分隔符:
IFS=: # split on :
set -o noglob # disable glob part
cmd='cat:a b'
printf '<%s>\n' $cmd # split+glob
$cmd # split+glob
cmd
或者,您可以包含一个 shell 命令行(shell 语言中的代码)并调用eval
来解释该代码,而不是依赖 split+glob:
cmd='cat "a b"'
eval "$cmd" # note the quotes to disable split+glob