扩展的glob不会按预期扩展

时间:2013-01-07 13:42:27

标签: bash glob

我有一个名为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

已打印。我做错了什么?

2 个答案:

答案 0 :(得分:2)

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

#!/usr/bin/env bash

# enable extended globbing
shopt -s extglob

PARAMS=$(tr ' ' '|' <<< $*)
printf '%s' !($PARAMS)

答案 1 :(得分:2)

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

另一个问题是,IFS被设置为|会导致扩展的globbing混乱,因此您必须在展开模式之前重置它。因此,您必须分两步进行扩展:首先,计算模式,然后重置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