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

4 Answers 4

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
4
  • Since the shell is bash, might as well awk '{ print $2 }' <<<"$pvs_var" Nov 30, 2018 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, 2018 at 23:22
  • @Peschke With single brackets, you'd want to add double-quotes around the $( ) expression. Dec 1, 2018 at 3:49
  • 1
    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, 2018 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).

(you need LVM 2.02.158 (2016) or newer for --reportformat json).

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=""}'
)

(you need LVM 2.02.107 (2014) or newer for -S).

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"

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .