我有一个名为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
已打印。我做错了什么?
答案 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