Issue using empty variable in grep command

Hi,
I'm writing a shell script and trying to grep a variable value, it works fine as long as there is a value in /tmp/list.out which is captured in $DSK but sometimes the file tends to be empty and that is where I'm having an issue while using grep which returns nothing. I know I can use something like [ -z "$DSK" ] to test if $DSK is empty but I'm trying to see if it would work this way.

#!/bin/ksh
DSK=`cat /tmp/list.out |grep disk | awk '{print $1}' |cut -c 7-`
for i in `lspv | awk '{print$1}' |grep -v "$DSK"`
 do
  echo $DSK
  if 
  then
        echo "Fail"
  else
        echo "Pass"
  fi
 done
fi

Your first line of code seems to boil down to:

DSK=$( awk '/disk/ {print substr($1, 7)' /tmp/list.out )

So that seems okay to me. You can have awk call exit 1 if it does not find something:

DSK=$( awk '/disk/ {print substr($1, 7); exit 0 } END{exit 1 }' /tmp/list.out  || echo 'bad DSK')

Then you know not to go on.

I cannot fathom what you are doing with the rest of the code-
it looks like you are trying to remove something from the output of lspv
derived from /tmp/list.out like maybe a volume group or a pvid.

And what do you want to do with the "blank" if statement? By that I mean what do you expect to find that will tell you DSK is empty? Or the result is bad.

You have to have a way to signal failure for the code to tell you it failed.
with the above first line:

[ "$DSK" = "bad DSK" ] && echo failure ||
for i in `lspv | awk '{print$1}' |grep -v "$DSK"`
 do
  echo $DSK
  if ????
  then
        echo "Fail"
        break
  else
        echo "Pass"
  fi
 done
fi

What is the i variable supposed to do here, BTW?

Thanks Jim for your response, here is what I'm trying to do, there is a particular disk of certain size in /tmp/list.out that I want to exclude and below is my actual script, it works fine when there is a value for variable DSK otherwise it does nothing if /tmp/list.out is empty i.e., if variable $DSK is empty and I want to continue with the script irrespective of data present in /tmp/list.out since there could other disks that has a failed path.

DSK=$( awk '/disk/ {print substr($1, 7)}' /tmp/list.out )
for i in `lspv | awk '{print$1}' |grep -v "$DSK"`
 do
  DSK_PATH=`lspath | grep -w $i | grep Ena | wc -l`
  if [ "$DSK_PATH" -lt 2 ]
  then
        echo "Failed path found"
  else
        echo "No failed path"
  fi
 done
fi

Within ` ` and $( ) you can run complete (sub-)shell code.

for i in `
  if [ -z "$DISK" ]
  then
    lspv | awk '{print$1}'
  else
    lspv | awk '{print$1}' | grep -vw "$DSK"
  fi
`
do
  ..
done

--
wc -l always returns a number, but it can be prefixed with space.
Therefore better do not quote the variable:

  if [ $DSK_PATH -lt 2 ]

--
On AIX I found the following is more efficient:

  DSK_PATH=`lspath -l "$i" | grep -c "^Enabled"`

Thank you MadeInGermany, your suggestion of checking variable value within these

` `

and

$( )

for (sub-)shell code helped me in getting this to work, you really made it simple and I think this is because of your Location being Simplicity:p

I'm trying to enhance the script i.e., if there is more than one value for DISK variable but it errors out on nested "for loop" saying "0403-057 Syntax error at line 13 : `for' is not matched"

for i in `
    for DISK in `awk '/disk/ {print substr($1, 7)}' /tmp/list.out`
    do
        if [ -z "$DISK" ]
        then
           lspv | awk '{print$1}'
        else
           lspv | awk '{print$1}' | grep -vw "$DISK"
        fi
    done
`
do
  .....
done

Swap line 2 and 3 in above.

I don't think we can swap lines 2 and 3 as 'do' for first "for loop" is further down, unless I didn't get what you wanted me to do.

Actually below code i.e., for variable 'i' is in between backticks

` `
for i in `
    for DISK in `awk '/disk/ {print substr($1, 7)}' /tmp/list.out`
    do
        if [ -z "$DISK" ]
        then
           lspv | awk '{print$1}'
        else
           lspv | awk '{print$1}' | grep -vw "$DISK"
        fi
    done
`

"for loop" for variable 'i' continues here

do
 .......
done

You might want to add a space between the '{print $1}' 's.
Edit: nevermind..

I got the nested "for loop" error part working by using

$( )

instead of backticks

` `

BUT cannot exclude all of the values at once coming from /tmp/list.out using grep -vw option in line 8.

for i in `
    for DISK in $( awk '/disk/ {print substr($1, 7)}' /tmp/list.out` )
    do
        if [ -z "$DISK" ]
        then
           lspv | awk '{print$1}'
        else
           lspv | awk '{print$1}' | grep -vw "$DISK"
        fi
    done
`
do
  .....
done

What do you mean by

?

Basically I'm just trying to exclude the values of /tmp/list.out from 'lspv' output which is line 8.

What is /tmp/list.out ?
How is it created?
Can you give an example?

I'm separating disks coming off a particular XIV storage array and redirecting output to /tmp/list.out as below

lsdev -Cc disk |grep 2810 |grep awk'{print$1}' > /tmp/list.out

and

cat /tmp/list.out
hdisk0
hdisk50
hdisk115

.

That can shrink to

lsdev -Cc disk | awk'/2810/ {print$1}' > /tmp/list.out

And if /tmp/list.out consists only of the disk names, then in the other part you can exclude them e.g. with

lspath | grep -vwf "/tmp/list.out"

or

lspv | grep -vwf "/tmp/list.out"

An example with an elegant while loop:

lspath |
 grep -vwf "/tmp/list.out" |
 while read status disk type
do
  echo "$disk"
  if [ "$status" != "Enabled" ] 
  then
    echo "Fail"
  else
    echo "Pass"
  fi
done
1 Like

This is what I was trying to achieve, Thank you so much for keeping it simple as well :slight_smile: