简体   繁体   English

扩展的glob无法按预期扩展

[英]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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM