tomsseisums
tomsseisums

Reputation: 13367

bash / sh -c not working with multiple pipes

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?

Upvotes: 8

Views: 2145

Answers (2)

Henk Langeveld
Henk Langeveld

Reputation: 8456

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.

Upvotes: 1

eduffy
eduffy

Reputation: 40232

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}'

Upvotes: 18

Related Questions