$ md="-l /tmp/test/my dir"
$ ls "$md"
ls: invalid option -- ' '
Try 'ls --help' for more information.
$ md="-l \"/tmp/test/my dir\""
$ ls "$md"
ls: invalid option -- ' '
Try 'ls --help' for more information.
我想知道为什么两者都不起作用?谢谢。请注意,变量的值包含
- 一个选项
-l
- 包含空格的路径名参数
- 一个空格将以上两者分开。
我的实际问题是:我写了一个脚本myscript.sh
#! /bin/bash
old_dest=""
while getopts ":l:t" opt; do
case $opt in
l)
old_dest="--link-dest \"$OPTARG\""
;;
esac
done
rsync -a --delete "$old_dest" /path/to/source /path/to/dest
我想将脚本作为-l
带有选项的命令来调用。
myscript.sh -l "/media/t/my external hdd/backup/old one"
我应该如何编写脚本中分配给 的部分old_dest
?
答案1
您的命令不起作用的原因是引号删除/单词拆分没有以递归方式应用。
因此"$old_dest"
扩展为以下 SINGLE 参数:
--link-dest "/media/t/my external hdd/backup/old one"
所有这些都是一个参数,因为变量用双引号引起来。 (那些双引号被删除,但是双引号扩张的结果,即变量值的一部分,不会被删除。)
如果你使用$old_dest
相反的方式,你会得到多个参数,但不是你想要的方式。你会得到以下五个参数:
--link-dest
"/media/t/my
external
hdd/backup/old
one"
这是因为您将获得变量扩展,然后进行分词,如手册中所述。你会不是获取变量扩展,然后解释变量中的引号。并且引号不会被删除,因此最终参数将是四个字符:one"
。
正如另一个答案所述,正确的方法是使用 Bash 数组。
另外,您可能会喜欢 Tcl 处理引号和分词的方式。它可能更直观,尽管我对 shell 分词非常熟悉,但我必须更多地考虑 Tcl 而不是 shell。
答案2
由于您使用的是 bash,并且 bash 支持数组,因此我建议将 old_dest 设为数组:
#! /bin/bash
old_dest=()
while getopts ":l:t" opt; do
case $opt in
l)
old_dest+=('--link-dest' "$OPTARG")
;;
esac
done
printf 'Element: %s\n' rsync -a --delete "${old_dest[@]}" /path/to/source /path/to/dest
我将对 rsync 的调用改为对 printf 的调用,以在单独的行上显示命令和每个参数。执行时:
./myscript.sh -l "/media/t/my external hdd/backup/old one"
结果是:
Element: rsync
Element: -a
Element: --delete
Element: --link-dest
Element: /media/t/my external hdd/backup/old one
Element: /path/to/source
Element: /path/to/dest