1

I'm trying to find a nice way of checking some text in order to set a variable. For instance to perform the logic: 'if the version string is 1.x then set a flag'. One way of doing this is:

versionFlag="0"
if grep -q "^1.*" versionfile; then
  versionFlag="1"
fi

which is a little verbose. If I want to switch on multiple possibilities then that's easier:

case `grep "^1.*" versionfile` in
  1.*)
    echo "version 1"
    ;;
...
esac

But is there a nice one line way of just setting a flag to be true or false if some text matches a regexp or a wildcard?

the_mandrill
  • 165
  • 5
  • 1
    You should be aware that in your second example, your grepping a regex then your case is using globbing. So grep might find "1a" or "10" successfully and then the case would (correctly) pass it to the default (presumably). You should probably put a literal dot in the grep like this `grep "^1\..*" ... ` – Dennis Williamson Feb 15 '10 at 14:21

4 Answers4

3
versionFlag=`grep "^1.*" /tmp/test | wc -l`

versionFlag is then set to 0. Any data in test matches, versionFlag is set to the number of lines that match, so

if [ $versionFlag == 0 ] ; then
  echo false
else
  echo true 
fi

edit: this can be done even more simply

versionFlag=$(grep "^1.*" /tmp/test -c)

which will return a count of instances in the file

Andy
  • 5,190
  • 23
  • 34
  • That's the way I used to do it before I discovered case and `grep -q`. It doesn't work quite as well on OS X since the output of `wc` contains leading spaces, so I had to pipe through sed, yada, yada... – the_mandrill Feb 15 '10 at 13:18
  • updated. perhaps the grep -c method will work in OSX :) – Andy Feb 15 '10 at 13:23
  • Lovely, the grep -c does the job. I didn't know you could do $(...) as well as the backtick operator too. – the_mandrill Feb 15 '10 at 13:36
  • 2
    The construct `$()` is much preferred over backticks. http://mywiki.wooledge.org/BashFAQ/082 – Dennis Williamson Feb 15 '10 at 14:15
2

You can do something like this in bash 3.x (older versions don't support regex matching)

version=`cat versionfile`
[[ $version =~ "^1.*" ]] && versionFlag=1
James
  • 7,553
  • 2
  • 24
  • 33
  • Thanks, I didn't know you could do direct regexp matches. Shame though that it doesn't provide a way of setting versionFlag to 0 if it doesn't match – the_mandrill Feb 15 '10 at 13:19
  • That won't work unless you remove the quotes. But then it will match version numbers like 1234abc.@(/: - Try: `[[ $version =~ ^1\..* ]]` (1 dot anything) or `[[ $version =~ ^1\.[[:digit:]]{1,3}$ ]]` (e.g. 1.1 or 1.789 but not 1.2345 or 1.1a). – Dennis Williamson Feb 15 '10 at 14:11
0

There isn't a ternary operator (e.g. ?:) in bash, so you are stuck with your if, then construct over multiple lines. You could use a different language that does have a ternary operator (PERL for example).

Mind you, a lot of folk discourage use of ternary operators as they aren't as easy to read in code - in other words, your comments end up longer than the multiple lines of code would have been.

I doubt there is a performance benefit of either method.

dunxd
  • 9,482
  • 21
  • 80
  • 117
0

Actually, this construct:

[[ $version =~ ^1\.+ ]] && versionFlag=1

is easily extended to support the "no-match" case; just do this:

[[ $version =~ ^1\.+ ]] && versionFlag=1 || versionFlag=0

Incidentally, note the change from '*' to '+' in the regex. Using the star, the regex will still incorrectly match on a version value of "10". (The '*' modifier means "match zero or more occurrences", i.e., you still don't need to have a decimal point; the '+' modifier means "match one or more occurrences".) Making this change will, however, mean that "1" (i.e., a value without a decimal) will not match; this might or might not be a problem for your application.

There is also a way to do this without using the regex-match operator, if you don't have it; try this:

[[ ${version#1.} != ${version} ]] && versionFlag=1 || versionFlag=0

This is just a pattern-match, not a regex, so if you really need regex functionality, it won't work, but for simple stuff, it's great. (If you're not familiar with this form of parameter expansion, the "${version#1.}" construct expands to the value of "version", but with the post-'#' pattern removed from the beginning of the value if it was originally there. Example: If "version" has a value of "1.03", the result of "${version#1.}" is "03". Since this differs from the original value, the "!=" test succeeds.)