2

This question already has an answer here:

I'm pretty familiar with regular expressions in various contexts, but bash substring matching just baffles me. Can someone please explain them to me, ideally with some examples? The examples I've found on google are very simple, and suggest pretty generic (if limited) regex matching, but when I try to use them in practical situations it never works. From my understanding substring matching should work as follows:

result=${string##pattern}

will find the longest substring of 'string', starting from its beginning, that matches 'pattern'. It removes that match from 'string' and puts the remainder in 'result'. But consider:

temp=${myvar##[^0-9]*} && echo $temp

As far as I can tell, my pattern should match 'zero or more characters that are not digits' - the longest such match from the start of the string. Then take as example:

myvar=my_file_123_45.txt

I should expect the characters 'my_file_' to be matched: that is the longest combination of characters from the start of 'string' that aren't digits. Instead, the returned result is empty! Everything gets matched! What happened to excluding digits?! In both gedit (using the search-and-replace regex engine), and in Labview's regex tools, the match pattern

pattern=^[^0-9]*

which i believe to be equivalent, results in my expected match - 'my_file_'. What's different about Bash?

marked as duplicate by Michael Homer, GAD3R, Jeff Schaller, don_crissti, Archemar Feb 27 '17 at 13:44

This question has been asked before and already has an answer. If those answers do not fully address your question, please ask a new question.

  • 2
    pattern in ${string##pattern} is supposed to be a path expansion pattern, not a regular expression. There are preciously few places in bash where you can meaningfully use regular expressions, and this is not one of them. Unrelated: beware that regular expressions come in many flavors. There are at least 50 different syntaxes for regular expressions, and they are mostly incompatible to one another. So you need to pay attention to those, too. – Satō Katsura Feb 27 '17 at 6:30
  • Your pattern mean any symbol except digital (just one character) which followed any symbol(s) (include none) so full string is match. To get result as you expected you'd use ${myvar##*[^0-9]_} – Costas Feb 27 '17 at 6:49
1

You need to realize that Bash substing matching DOES NOT make use of regexes. Rather, it uses wildcard expansion in tandem with # ## %% % to look at shortest and longest matches and from either direction.

In your specific case of wanting to grab the leading non-digits you could employ the following stratagem:

echo "${myVar%%[0-9]*}"; # delete upto the leftmost digit starting from right

output

my_file_

I find the following site: http://www.tldp.org/LDP/abs/html/parameter-substitution.html especially handy for all matters Bash parameter related.

  • Ah, that explains it! Of course, in this case the submatches I really want are pair of numbers, so there's still a bit of fiddling, but now at least I'll know to match using wildcard expressions, not regular expressions. – marcus Feb 27 '17 at 7:44

Not the answer you're looking for? Browse other questions tagged or ask your own question.