Reputation: 13367
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
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
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