情况如下(我使用的是 Mac,OS X El Capitan):
# This works:
$ cd /Applications/Adobe\ Illustrator*/Cool\ Extras.localized/en_US/Templates/;
# These do not work:
$ INSTALL_DIR=/Applications/Adobe\ Illustrator*/Cool\ Extras.localized/en_US/Templates;
$ cd $INSTALL_DIR
# Moves me here: /Applications/Adobe
$ cd "$INSTALL_DIR"
-bash: cd: /Applications/Adobe Illustrator*/Cool Extras.localized/en_US/Templates: No such file or directory
$ cd "${INSTALL_DIR}"
-bash: cd: /Applications/Adobe Illustrator*/Cool Extras.localized/en_US/Templates: No such file or directory
$INSTALL_DIR
我的目标是像这样使用tar
:
$ tar -xz $SOURCE_ZIP --strip-components 1 -C $INSTALL_DIR "*.ait";
不幸的是,-C
(更改为目标目录)不喜欢$INSTALL_DIR
;中的空格。如果我使用引号,我就无法*
工作。
有没有一种优雅的方法来处理这种情况?
答案1
当 * 没有被引用时,shell 在运行命令之前扩展参数列表。它将扩展参数列表传递给程序。
当 * 出现在带引号的字符串中时,它在传递给程序之前不会被 shell 扩展。
尝试扩展路径,将其分配给另一个变量,然后在将其作为参数传递时引用第二个变量。
答案2
问题不在于 tar,而在于你的 shell 代码。该选项的参数-C
应该是路径,而不是通配符模式。请注意,您在使用该命令时遇到了完全相同的问题cd
。
您在变量中存储了通配符模式INSTALL_DIR
。当您编写 时-C $INSTALL_DIR
,这将应用“split+glob”运算符:获取变量的值,在空格处拆分它,并将每个单词解释为通配符模式,然后进行扩展。这里变量的值为/Applications/Adobe Illustrator*/Cool Extras.localized/en_US/Templates
,分为三个词/Applications/Adobe
, Illustrator*/Cool
, Extras.localized/en_US/Templates
;中间的单词包含通配符 ( *
),因此它被解释为通配符模式,但由于它不匹配任何文件,因此该模式保持原样。这使得选项的参数-C
成为 string /Applications/Adobe
,然后命令还有两个参数tar
:Illustrator*/Cool
和Extras.localized/en_US/Templates
。
如果使用双引号,则"$INSTALL_DIR"
只是变量的值INSTALL_DIR
。仍然*
在里面,因为它在任何时候都没有扩展过。
根据经验,通配符会在需要多个单词的上下文中扩展。毕竟,一般来说,通配符模式匹配多个文件。赋值的右侧会抑制通配符扩展,因为结果预计是单个字符串。要获取列表,请分配给数组变量而不是字符串变量:
INSTALL_DIRS=(/Applications/Adobe\ Illustrator*/Cool\ Extras.localized/en_US/Templates)
如果您安装了多个版本的 Illustrator,则可能有多个数组元素。让我们看最后一个元素。
INSTALL_DIR=${INSTALL_DIRS[$((${#INSTALL_DIRS}-1))]}
NowINSTALL_DIR
是现有文件的路径(假设通配符确实匹配)。您可以正常使用它(即您可以将其展开在双引号内)。
tar -xz "$SOURCE_ZIP" --strip-components 1 -C "$INSTALL_DIR" "*.ait"