3

This command works as expected:

(dpkg -l | egrep "linux.+3.8.0.*44" | awk '{print $2}')
linux-generic-lts-raring
linux-headers-3.8.0-44
linux-headers-3.8.0-44-generic
linux-headers-generic-lts-raring
linux-image-3.8.0-44-generic
linux-image-generic-lts-raring

However, when I run it with bash -c it doesn't work:

bash -c "(dpkg -l | egrep "linux.+3.8.0.*44" | awk '{print $2}')"
ii  linux-generic-lts-raring         3.8.0.44.44                       Generic     Linux kernel image and headers
ii  linux-headers-3.8.0-44           3.8.0-44.66~precise1              Header files related to Linux kernel version 3.8.0
ii  linux-headers-3.8.0-44-generic   3.8.0-44.66~precise1              Linux kernel headers for version 3.8.0 on 64 bit x86 SMP
ii  linux-headers-generic-lts-raring 3.8.0.44.44                       Generic Linux kernel headers
ii  linux-image-3.8.0-44-generic     3.8.0-44.66~precise1              Linux kernel image for version 3.8.0 on 64 bit x86 SMP
ii  linux-image-generic-lts-raring   3.8.0.44.44                       Generic Linux kernel image

I have no clue why. It's almost as if the pipe is breaking.

Charles Duffy
  • 280,126
  • 43
  • 390
  • 441
Mark Nichols
  • 1,407
  • 2
  • 19
  • 25
  • Could you generate an example that people who aren't on Debian-derived distros can copy/paste/run? – Charles Duffy Nov 10 '16 at 17:13
  • That said, one very obvious problem is the quotes passed to `egrep` being of the same type used on the outside. – Charles Duffy Nov 10 '16 at 17:14
  • ...why use both grep and awk as separate commands, anyhow? `bash -c "dpkg -l | awk '/linux.+3[.]8[.]0.*44/ { print $2 }'"`. Oh. Except the ` $2` doesn't work there. – Charles Duffy Nov 10 '16 at 17:14
  • @JohnKugelman, ...indeed, but unless the OP has some unusual filenames in their current working directory, `linux.+3.8.0.*44` looks to me like it's not likely to be expanding incorrectly unquoted (as they're inadvertently doing). Unless, of course, `IFS` is at a non-default value that contains any characters present in the string. – Charles Duffy Nov 10 '16 at 17:15
  • I don't have a non-Debian box at my disposal. – Mark Nichols Nov 10 '16 at 17:18
  • Changing the double-quotes to single-quotes doesn't fix the issue – Mark Nichols Nov 10 '16 at 17:18
  • You could replace `dpkg -l` with `printf '%s\n' "foo bar baz"`, and that would suffice to make a non-Debian-specific example. – Charles Duffy Nov 10 '16 at 17:18
  • Of course it doesn't, because then you have other problems with your *embedded* single quotes. That doesn't mean the outer double quotes aren't the problem; it just means changing them to single quotes without any other alterations isn't the solution. – Charles Duffy Nov 10 '16 at 17:18
  • The suggested command, `bash -c "dpkg -l | awk '/linux.+3[.]8[.]0.*44/ { print $2 }'"` doesn't work as I want - I still get all the columns, not just the second one – Mark Nichols Nov 10 '16 at 17:19
  • ...you see the edit above, with the "Oh. Except the `$2` doesn't work there`, in my comment? That edit is saying that I know that the above code won't work, and why it didn't work, making an amendment telling me that it doesn't work... rather redundant. – Charles Duffy Nov 10 '16 at 17:21
  • ...so, let me explain the "why" one more time: In `bash -c "(dpkg -l | egrep "linux.+3.8.0.*44" | awk '{print $2}')"`, the invoking shell (not the bash you're starting, but the one that read your `bash -c` command) expands the `$2`, making the command it runs `bash -c "(dpkg -l | egrep "linux.+3.8.0.*44" | awk '{print }')"`, which prints the whole line of input, not only `$2`. – Charles Duffy Nov 10 '16 at 17:29
  • ...there are other bugs, like `3.8.0` not escaping the `.`s you mean to be literal and thus being willing to match, say, `348-0` just as much as `3.8.0`, and the double-quotes you're passing to `grep` closing the double quotes that started your `grep -c` command so that the string you're grepping for is expanded unquoted, but those aren't the immediate problem. – Charles Duffy Nov 10 '16 at 17:31

1 Answers1

8

Because you're in double quotes, $2 gets expanded by the shell, not passed literally to awk. And print in awk, by default, prints $0, ie. the entire line of input, so if it's expanded to an empty value, there's your problem.

bash -c "(dpkg -l | egrep 'linux.+3.8.0.*44' | awk '{print \$2}')"

By the way -- there's no point to using grep and awk separately.

bash -c "dpkg -l | awk '/linux.+3.8.0.*44/ { print \$2 }'"

If your enclosing shell is itself bash, then one can use $'' as an alternate means to provide literal strings:

# $'' only works with bash, ksh, etc., but won't interpret $2, and lets
# you pass literal quotes
bash -c $'dpkg -l | awk \'/linux.+3[.]8[.]0.*44/ { print $2 }\''

By contrast, if your enclosing shell is baseline POSIX, including literal single-quotes inside a single-quoted string gets a bit more complicated.

bash -c 'dpkg -l | awk '"'"'/linux.+3[.]8[.]0.*44/ { print $2 }'"'"''
Charles Duffy
  • 280,126
  • 43
  • 390
  • 441