2

I found a good answer that explains how to remove a specified pattern from a string variable. In this case, to remove 'foo' we use the following:

string="fooSTUFF"
string="${string#foo}"

However, I would like to add the "OR" functionality that would be able to remove 'foo' OR 'boo' in the cases when my string starts with any of them, and leave the string as is, if it does not start with 'foo' or 'boo'. So, the modified script should look something like that:

string="fooSTUFF"
string="${string#(foo OR boo)}"

How could this be properly implemented?

Community
  • 1
  • 1
Nazar
  • 820
  • 5
  • 13
  • 36

3 Answers3

3

If you have set the extglob (extended glob) shell option with

shopt -s extglob

Then you can write:

string="${string#@(foo|boo)}"

The extended patterns are documented in the bash manual; they take the form:

  • ?(pattern-list): Matches zero or one occurrence of the given patterns.

  • *(pattern-list): Matches zero or more occurrences of the given patterns.

  • +(pattern-list): Matches one or more occurrences of the given patterns.

  • @(pattern-list): Matches one of the given patterns.

  • !(pattern-list): Matches anything except one of the given patterns.

In all cases, pattern-list is a list of patterns separated by |

rici
  • 234,347
  • 28
  • 237
  • 341
  • Thank you for the reference to the manual. Could you, please, expand your answer on the "(enabled with shopt -s extglob)" matter? Where in the script it should be placed? Do I need to disable it at some point? how to do that? – Nazar Feb 16 '17 at 15:29
  • @Naz: If you have a script, you can put the line anywhere in the script (before the use of the extended pattern, of course). Normally you don't need to disable it, because it's pretty rare to see something which looks like an extended pattern, but if it interferes with some other script you can disable it with `shopt -u extglob` (-s: set, -u unset). In many distributions (debian/ubuntu, for example), you'll find that it is enabled in interactive shells because it is used by command completion scripts. But in non-interactive shells you'll need to enable it in the script. – rici Feb 16 '17 at 15:33
2

You need an extended glob pattern for that (enabled with shopt -s extglob):

$ str1=fooSTUFF
$ str2=booSTUFF
$ str3=barSTUFF
$ echo "${str1#@(foo|boo)}"
STUFF
$ echo "${str2#@(foo|boo)}"
STUFF
$ echo "${str3#@(foo|boo)}"
barSTUFF

The @(pat1|pat2) matches one of the patterns separated by |.

@(pat1|pat2) is the general solution for your question (multiple patterns); in some simple cases, you can get away without extended globs:

echo "${str#[fb]oo}"

would work for your specific example, too.

Benjamin W.
  • 46,058
  • 19
  • 106
  • 116
  • Thank you for the reference to the manual. Could you, please, expand your answer on the "(enabled with shopt -s extglob)" matter? Where in the script it should be placed? Do I need to disable it at some point? how to do that? – Nazar Feb 16 '17 at 15:21
  • @Naz The `shopt -s extglob` command has to be issued at any point before you use the `@(...)` pattern. I won't hurt to keep it turned on, but if you want to explicitly turn it off, just issue `shopt -u extglob`. Notice that extended globs are automatically enabled for `[[ $var = pattern ]]` conditionals. See the [manual](https://www.gnu.org/software/bash/manual/bashref.html#The-Shopt-Builtin) for more information about the `shopt` command. – Benjamin W. Feb 16 '17 at 15:34
-1

You can use:

string=$(echo $string | tr -d "foo|boo")