4

我有一个名为 except.sh 的 bash 脚本,它传递了一个文件/目录列表,如下所示:

$ ls
a b c d/
$ ./except.sh b c

当以这种方式调用时,它应该扩展到a d/即除给定名称之外的所有文件/目录。

这是我尝试实现的方法:

#!/usr/bin/env bash

# enable extended globbing
shopt -s extglob

# set IFS to | so that $* expands correctly
IFS='|'

printf '%s' !("$*")

作为b c参数,最后一行应该扩展为

printf '%s' !(b|c)

导致a d被打印。但令我惊讶的是,

abcd

被打印。我究竟做错了什么?

4

2 回答 2

3

问题是$*双引号,这意味着它的内容不会被视为一个模式,就像echo "*"不扩展星号一样。将外部模式与内部引用部分结合起来会自动转义后者,因此!("b|c")被视为!(b\|c). 对不存在b|c文件的否定自然会扩展到目录中的所有文件。

IFS另一个问题是扩展的通配符被设置为 搞砸了|,所以你必须在扩展模式之前重置它。因此,您必须分两步进行扩展:首先,计算模式,然后重置IFS并扩展它:

#!/usr/bin/env bash

# enable extended globbing
shopt -s extglob

# temporarily set IFS to | so that $* expands to part an extended pattern
old_ifs=$IFS
IFS='|'
pattern="!($*)"
IFS=$old_ifs

printf '%s' $pattern
于 2013-01-15T14:48:32.933 回答
2

问题是由于IFS变量覆盖(覆盖此变量后,bash 模式匹配行为奇怪,例如,ls -d !(b|c)在设置之前和之后尝试IFS),以下应该工作:

#!/usr/bin/env bash

# enable extended globbing
shopt -s extglob

PARAMS=$(tr ' ' '|' <<< $*)
printf '%s' !($PARAMS)
于 2013-01-07T15:02:56.757 回答