[英]Extended glob does not expand as expected
I have a bash script named except.sh which is passed a list of files/directories like so: 我有一个名为except.sh的bash脚本,该脚本传递了文件/目录列表,如下所示:
$ ls
a b c d/
$ ./except.sh b c
When calling except this way, it should expand to ad/
ie all files/directories except the given names. 当以这种方式调用时,它应该扩展到
ad/
即除给定名称之外的所有文件/目录。
Here's how I tried to implement this: 这是我尝试实现的方法:
#!/usr/bin/env bash
# enable extended globbing
shopt -s extglob
# set IFS to | so that $* expands correctly
IFS='|'
printf '%s' !("$*")
Given bc
as parameters, the last line should expand to 给定
bc
作为参数,最后一行应扩展为
printf '%s' !(b|c)
resulting in ad
being printed. 导致
ad
被打印。 But to my suprise, 但令我惊讶的是
abcd
is printed. 打印。 What am I doing wrong?
我究竟做错了什么?
The problem is due to the IFS
variable override (after you override this variable, bash pattern matching behaves odd, example, try ls -d !(b|c)
before and after setting IFS
), the following should work: 问题是由于
IFS
变量覆盖(在覆盖此变量之后,bash模式匹配的行为很奇怪,例如,在设置IFS
之前和之后尝试ls -d !(b|c)
),以下方法应该起作用:
#!/usr/bin/env bash
# enable extended globbing
shopt -s extglob
PARAMS=$(tr ' ' '|' <<< $*)
printf '%s' !($PARAMS)
The problem is that $*
is in double quotes, which means that its contents will not be treated as a pattern, just like echo "*"
does not expand the asterisk. 问题在于
$*
用双引号引起来,这意味着它的内容不会被当作模式来对待,就像echo "*"
不会扩展星号一样。 Combining the outer pattern with the inner quoted portion automatically escapes the latter, so !("b|c")
is treated like !(b\\|c)
. 将外部模式与内部带引号的部分合并会自动使后者避开,因此
!("b|c")
就像!(b\\|c)
一样对待。 Negation of the nonexistent b|c
file naturally expands to all files in the directory. 不存在的
b|c
文件的否定自然会扩展到目录中的所有文件。
An additional problem is that extended globbing is messed up by IFS
being set to |
另一个问题是,将
IFS
设置为|
,会使扩展的全局混乱|
, so you must reset it before expanding the pattern. ,因此您必须在扩展图案之前将其重置。 Therefore, you must do the expansion in two steps: first, calculate the pattern, then reset
IFS
and expand it: 因此,您必须分两步进行扩展:首先,计算模式,然后重置
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
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.