2

Consider the following on a debian based system:

VAR=$(dpkg --get-selections | awk '{print $1}' | grep linux-image)

This will print a list of installed packages with the string "linux-image" in them on my system this output looks like:

linux-image-3.11.0-17-generic
linux-image-extra-3.11.0-17-generic
linux-image-generic

Now as we all know

echo $VAR

results in

linux-image-3.11.0-17-generic linux-image-extra-3.11.0-17-generic linux-image-generic

and

echo "$VAR"

results in

linux-image-3.11.0-17-generic
linux-image-extra-3.11.0-17-generic
linux-image-generic

I do not want to use external commands in a if clause, it seems rather dirty and not very elegant, so I wanted to use bash built in regex matching:

if [[ "$VAR" =~ ^linux-image-g ]]; then
   echo "yes"
fi

however that does not work, since it does not seem to consider multiple lines here. How can I match beginnings of lines in a variable?

GEO
  • 121
  • 1
  • 3
  • `[[ $var == linux-image-g* ]]` should make. See [In bash, how can I check if a string begins with some value?](http://stackoverflow.com/questions/2172352/in-bash-how-can-i-check-if-a-string-begins-with-some-value) – fedorqui Aug 27 '14 at 13:20
  • 1
    That'll just match at the start of the string. That still won't do what he wants. – Etan Reisner Aug 27 '14 at 13:21
  • 1
    `[[ "$VAR" =~ $'\n'linux-image-g ]]` should work, assuming you don't want to use `read` to work on the variable contents line-by-line. – Etan Reisner Aug 27 '14 at 13:22
  • 1
    Could just use awk for the whole thing `dpkg --get-selections | awk '$1~/^linux-image-g/{print "yes"}' ` –  Aug 27 '14 at 13:31
  • Etan Reisner: Thanks that is what I need! If you would turn that into an answer I can accept that. – GEO Aug 27 '14 at 15:50

1 Answers1

3

There's nothing wrong with using an external command as part of the if statement; I would skip the VAR variable altogether and use

if dpkg --get-selections | awk '{print $1}' | grep -q linux-image;

The -q option to grep suppresses its output, and the if statement uses the exit status of grep directly. You could also drop the grep and test $1 directly in the awk script:

if dpkg --get-selections | awk '$1 =~ "^linux-image" { exit 0; } END {exit 1}'; then

or you can skip awk, since there doesn't seem to be a real need to drop the other fields before calling grep:

if dpkg --get-selections | grep -q '^linux-image'; then
chepner
  • 497,756
  • 71
  • 530
  • 681
  • Thanks for your answer. For the example situation I gave you this would be the way to go. Though I have to mention the whole picture to make clear why this is a no go for me: The command the prints to $VAR takes quite long to dump stuff from a large database (around 1 second), and my if clause is in a for loop that loops through thousands of entries, so that would add up to quite some difference, while only calling the database to dump the stuff I need one time in a variable is A LOT faster. – GEO Aug 27 '14 at 15:44
  • You might want to consider using a language with proper data structures, to allow faster querying of the set of strings returned by `dpkg`. You might be able to get away with using an associative array in `bash`, with each package name as a key. – chepner Aug 27 '14 at 16:01
  • chepner: the mentioned command is an ´apt-cache´ one (I took dpkg --get-selections only as a fast example) The solution of Etan Reisner in the comments suits me pretty well and does the job. – GEO Aug 27 '14 at 16:11