奇怪的Bash模式替换行为

奇怪的Bash模式替换行为,bash,Bash,此函数f()应该非常简单,但其工作方式却令人费解: f() { a=(cyan red green blue orange violet) shopt -s extglob echo 1: -${a[@]/!($1)}- echo 2: -${a[@]/!($1)/}- echo 3: -${a[@]/!("$1")/}- echo 4: -"${a[@]/!($1)/}"- echo 5: -${a[@]/!($1)/x}- } echo ORANGE f oran

此函数
f()
应该非常简单,但其工作方式却令人费解:

f() {
  a=(cyan red green blue orange violet)
  shopt -s extglob
  echo 1: -${a[@]/!($1)}-
  echo 2: -${a[@]/!($1)/}-
  echo 3: -${a[@]/!("$1")/}-
  echo 4: -"${a[@]/!($1)/}"-
  echo 5: -${a[@]/!($1)/x}-
}
echo ORANGE
f orange # ends in e like blue
echo YELLOW
f yellow
输出为(请注意空格/间距):

为什么只搜索单词的最后一个字符?!(在这种情况下,橙色的
e

预期的输出是
orange
,而不仅仅是
e


注意:我还希望在某些地方没有看到空白。问题是模式没有被锚定,因此例如对于
orange
,与
orange
不匹配的最长字符串是
orange
。因此,它被删除,并且只有
e
保留在那里。由于无法在bash中指定锚定,因此必须自己创建锚定:

#! /bin/bash
f() {
    a=(cyan red green blue orange violet '1 2')
    a=("${a[@]/#/|}")
    a=("${a[@]/%/|}")
    shopt -s extglob
    echo ["${a[@]/|!($1)|/-}"]
}
echo ORANGE
f orange # ends in e like blue
echo YELLOW
f yellow

不,壳模式始终隐式地锚定在两端。您的extglob也没有生效。不要将其设置在函数中。感谢您的启发性见解。。我看不到你明显能看到的东西。但是,如果不像您那样实质性地更改接受的值,即预先添加/追加一个分隔符,那么就没有办法锚定该模式了吗?@Robottinosino:我不知道。当我需要进行更复杂的字符串操作时,我通常使用Perl;echo${foo/ga}打印
allitor
@chepner:您可以分别使用
/#
/%
锚定左端或右端,但不能同时使用这两个。正如下面的注释中所暗示的@ormaj,
shopt-s extglob
在函数内部不起作用。遵循extglob的代码编译方式不同,声明时只编译一个函数(一次)。在运行时这样做已经太晚了。这并不是你问题的答案,仍然对这个问题感到困惑…@cdarke:那么为什么我的代码可以工作,但是如果我删除
shopt
行,它就不再工作了?有趣的是,你在使用哪个版本的Bash?这里是一样的:
OSX:10.8.3;Bash:4.2.42(2)-发行版
Linux v3.5.0-25-generic Ubuntu 12.10;Bash:4.2.37(1)-发行版
4.2.24这里是x86_64-suse-linux-gnu和4.1.5(1)-发行版(i486 pc linux gnu)
#! /bin/bash
f() {
    a=(cyan red green blue orange violet '1 2')
    a=("${a[@]/#/|}")
    a=("${a[@]/%/|}")
    shopt -s extglob
    echo ["${a[@]/|!($1)|/-}"]
}
echo ORANGE
f orange # ends in e like blue
echo YELLOW
f yellow