Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

bash / sh -c not working with multiple pipes

Tags:

linux

bash

shell

So, the commands:

dmesg | grep 'Attached SCSI disk' | awk '{ print $5}'

when executed directly from shell, works like it should, outputting:

[sdb]
[sdc]
[sda]

But, when I'm launching it with:

sh -c "dmesg | grep 'Attached SCSI disk' | awk '{ print $5}'"
# or
bash -c "dmesg | grep 'Attached SCSI disk' | awk '{ print $5}'"

I get:

[ 2.460353] sd 1:0:0:0: [sdb] Attached SCSI disk
[ 2.461348] sd 2:0:0:0: [sdc] Attached SCSI disk
[ 2.464181] sd 0:0:0:0: [sda] Attached SCSI disk

That clearly shows that the last pipe has not executed.

What am I doing wrong?

like image 473
tomsseisums Avatar asked Aug 23 '12 12:08

tomsseisums


2 Answers

Your $5 is getting evaluated too early. Change it to \$5.

If you were to replace bash with echo, you would see that $5 is being replace by the empty string:

 % echo "dmesg | grep 'Attached SCSI disk' | awk '{ print $5}'"
 dmesg | grep 'Attached SCSI disk' | awk '{ print }'

So, when bash evaluates the command, awk is going to print the entire line, not the fifth field.

When you escape the dollar sign (by pre-prending with a backslash), the variable $5 is preserved:

% echo "dmesg | grep 'Attached SCSI disk' | awk '{ print \$5}'"
dmesg | grep 'Attached SCSI disk' | awk '{ print $5}'
like image 121
eduffy Avatar answered Nov 04 '22 17:11

eduffy


There is a conflict between the shell and awk in their use and interpretation of $1, $2, ...

In all Bourne descendants (ash, bash, dash, ksh93, zsh), these indicate the numbered arguments as passed on the command line, while $0 is replaced with the name of the currently running script or the name of the interactive shell.

In awk, $1, $2, ... refer to the corresponding field of the current record, i.e. the first, second, etc., word of the current input line. $0 always refers to the whole record, including any Field Separators.

When calling awk from a shell (script) you must make sure that the awk script is properly quoted. To prevent shell interpolation, enclose the awk code inside single quotes.

like image 42
Henk Langeveld Avatar answered Nov 04 '22 19:11

Henk Langeveld