我可以从命令行提示符运行此命令:
cp -r folder/!(exclude-me) ./
递归复制所有内容folder
除了exclude-me
为当前目录中命名的子目录。这完全按照预期工作。但是,我需要它在我编写的 bash 脚本中工作,其中我有以下内容:
if [ -d "folder" ]; then
cp -r folder/!(exclude-me) ./
rm -rf folder
fi
但是当我运行脚本时:
bash my-script.sh
我明白了:
my-script.sh: line 30: syntax error near unexpected token `('
my-script.sh: line 30: ` cp -r folder/!(exclude-me) ./'
我不知道为什么它可以在命令提示符下工作,但完全相同的行在 bash 脚本中不起作用。
答案1
这是因为您使用的语法取决于未激活的特定 bash 功能。您可以通过将相关命令添加到脚本中来激活它:
## Enable extended globbing features
shopt -s extglob
if [ -d "folder" ]; then
cp -r folder/!(exclude-me) ./ &&
rm -rf folder
fi
这是以下的相关部分man bash
:
If the extglob shell option is enabled using the shopt builtin, several extended pattern matching operators are recognized. In the following description, a pattern-list is a list of one or more patterns separated by a |. Composite patterns may be formed using one or more of the fol‐ lowing sub-patterns: ?(pattern-list) Matches zero or one occurrence of the given patterns *(pattern-list) Matches zero or more occurrences of the given patterns +(pattern-list) Matches one or more occurrences of the given patterns @(pattern-list) Matches one of the given patterns !(pattern-list) Matches anything except one of the given patterns
在您的情况下,在 bash 的交互式调用中启用它的原因可能是因为您有shopt -s extglob
或~/.bashrc
因为您正在使用https://github.com/scop/bash-completion(bash-completion
至少在基于 Debian 的操作系统中的软件包中可以找到)包含 via~/.bashrc
或/etc/bash.bashrc
whichextglob
初始化时启用。
请注意,这些 ksh 风格的扩展 glob 运算符也可以在构建时通过传递--disable-extended-glob
给configure
bash 源代码中的脚本来完全禁用,或者使用--enable-extended-glob-default
.
但请注意,这extglob
违反了 POSIX 合规性。例如,虽然echo !(x)
POSIXsh
语言中未指定 的行为,
a='!(x)'
echo $a
需要输出!(x)
假设默认值$IFS
,而不是当前目录中除 之外的文件名列表,因此对于打算用作 的x
构建不应执行此操作。在 ksh 中,这些运算符默认启用,但在扩展时无法识别。bash
sh
X(...)