5

I need to compare a command output with a string. This is the scenario:

pvs_var=$(pvs | grep "sdb1") 

so pvs var is: /dev/sdb1 vg_name lvm2 a-- 100.00g 0

if [[ $($pvs_var | awk '{ print $2 }') = vg_name ]]; then
    do something
fi

The issue is that the output of the if statement is

-bash: /dev/sdb1: Permission denied

I don't understand this behavior. Thank you

12

You are attempting to execute the contents of $pvs_var as a command, rather than passing the string to awk.

To fix this, add an echo or printf in your if statement:

if [[ $(echo "$pvs_var" | awk '{ print $2 }') = vg_name ]]; then
    do something
fi
  • Since the shell is bash, might as well awk '{ print $2 }' <<<"$pvs_var" – D. Ben Knoble Nov 30 '18 at 23:13
  • @D.BenKnoble: Even better, we can replace the double brackets with single brackets and then it’s POSIX compliant. – Peschke Nov 30 '18 at 23:22
  • @Peschke With single brackets, you'd want to add double-quotes around the $( ) expression. – Gordon Davisson Dec 1 '18 at 3:49
  • You definitely want printf in the general case. Echo can do strange things if the variable contains backslashes or starts with a dash. – Kevin Dec 1 '18 at 17:08
4

Get the output in JSON format, and then you'll be able to extract information in a more reliable way:

pv_info=$(pvs -o pv_all,vg_all --unit b --nosuffix --reportformat json)
sdb1_vg=$(
  printf '%s\n' "$pv_info" |
   jq -r '.report[].pv[]|select(.pv_name == "/dev/sdb1").vg_name'
)

if [ "$sdb1_vg" = vg_name ]; then...

Or use a proper programming language with a JSON library instead of a shell (ksh93 does have JSON support though in its upcoming version).

If it's just that one query you want to do, pvs can also do all the work for you:

sdb1_vg=$(
  pvs -o vg_name -S pv_name=/dev/sdb1 --no-heading --config 'log{prefix=""}'
)

Also remember to quote your variables and avoid echo.

2

If you want to compare the VG from the output, then it might be easier to pre-process that:

# if you still need it
pvs_var=$(pvs | grep "sdb1") 
vg_name=$(pvs | grep "sdb1" | awk '{print $2}')
if [ "$vg_name" = "vg_name" ]; then
  echo do something
fi

What you were doing with

$($pvs_var | awk '{ print $2 }')

was initiating a command substitution $( ... ) whose first command was $pvs_var. Bash dutifully substituted the value of the variable and then attempted to execute it. That's not what you wanted.

Another alternative would be to send the variable as a here-string to the awk command:

# ...
if [ $(awk '{print $2}' <<< "$pvs_var") = "vg_name" ]; then
# ...

Here, the command substitution is calling awk and passing it input on stdin -- the contents of the $pvs_var variable.

0

You can try only with awk :

pvs | awk -v search='vg_name' '/sdb1/&&$2==search{exit 1}' || echo "ok"

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.