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?
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}'
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.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With