Robottinosino
Robottinosino

Reputation: 10882

Curious Bash pattern substitution behaviour

This function f() should be extremely simple yet it works in baffling ways:

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

The output is (please also note the blank/spacing):

ORANGE
1: - e -
2: - e -
3: - e -
4: -    e -
5: -x x x x xe x-
YELLOW
1: - -
2: - -
3: - -
4: -     -
5: -x x x x x x-

Why the last character of the sought word only?! (in this case e of orange)

The expect output is orange rather than just e

Note: I would also expect to see no blanks in some places where I see one blank there..

Upvotes: 0

Views: 97

Answers (1)

choroba
choroba

Reputation: 241818

The problem is that the pattern is not anchored, so for example for orange, the longest string that does not match orange is orang. It is therefore removed and only e remains there. As there is no way how to specify anchors in bash, you have to create them yourself:

#! /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

Upvotes: 2

Related Questions