scope of variable in pipe

后端 未结 6 1472
余生分开走
余生分开走 2020-12-18 10:51

The following shell scrip will check the disk space and change the variable diskfull to 1 if the usage is more than 10% The last echo always shows

相关标签:
6条回答
  • 2020-12-18 11:11

    @OP, use an outer brace or ()

    count=0
    max=10
    diskfull=0
    df -HP | { while read disk b c d used e
    do    
        if [ "$count" -gt 1 ];then
            used=${used%?}
            if [ "$used" -gt "$max" ];then
                echo "overload: $disk, used: $used%"
                diskfull=1
            fi
        fi
        count=$(( count+1 ))
    done 
    echo "diskfull: $diskfull" 
    }
    
    0 讨论(0)
  • 2020-12-18 11:13

    This is a side-effect of using while in a pipeline. There are two workarounds:

    1) put the while loop and all the variables it uses in a separate scope as demonstrated by levislevis86

    some | complicated | pipeline | {
        while read line; do
            foo=$( some calculation )
        done
        do_something_with $foo
    }
    # $foo not available here
    

    2) if your shell allows it, use process substitution and you can redirect the output of your pipeline to the input of the while loop

    while read line; do
        foo=$( some calculation )}
    done < <(some | complicated | pipeline)
    do_something_with $foo
    
    0 讨论(0)
  • 2020-12-18 11:13

    you can do it this way with gawk(no need to use grep). for alerts you can send email to root.

    threshold=10
    df -HP | awk -v t="$threshold" -v msg="" 'NR>1 && $5+0 > t{ 
        msg=msg $1" is "$5"\n"
    }END{print msg}' | mail root 
    

    or check whether there is "msg" or not first

    threshold=10
    result=$(df -HP | awk -v t="$threshold" -v msg="" 'NR>1 && $5+0 > t{ 
        msg=msg $1" is "$5"\n"
    }END{print msg}')
    if [ -n "$result" ];then
      echo "Overload"
      echo "$result" | mail root
    
    fi
    
    0 讨论(0)
  • 2020-12-18 11:15

    I think you must not be getting to the diskfull=1 line, because if you were, you would get no output at all-- the following exit line would exit the script.

    I don't know why this isn't working, but note that awk can handle the rest of the work:

    diskfull=$(df -HP | grep -vE '^Filesystem|tmpfs|cdrom' | awk 'BEGIN { x = 0 } { if ($5 + 0 >= '$ALERT') { x = 1 } } END { print x }')
    

    This way you don't need the while loop.

    0 讨论(0)
  • 2020-12-18 11:20

    When using pipes the shell seams to use sub-shells to do the work. As $diskfull is not known to these sub-shells the value is never changed.

    See: http://www.nucleardonkey.net/blog/2007/08/variable_scope_in_bash.html

    I modified your script as follows. It works for me and should work on your system too.

    #!/bin/sh
    diskfull=0
    
    ALERT=10
    stats=`df -HP | grep -vE '^Filesystem|tmpfs|cdrom|none|udev' | awk '{ print $5 "_" $1 }'`
    for output in $stats
    do
      usep=$(echo $output | awk '{ print $1}' | cut -d'%' -f1  )
      partition=$(echo $output | sed s/.*_// )
      #echo $partition -  $usep
      if [ $usep -le $ALERT ]; then
         diskfull=1
         break
      fi
    done
    echo $diskfull
    
    0 讨论(0)
  • 2020-12-18 11:20

    In this line:

    usep=$(echo $output | awk '{ print $1}' | cut -d'%' -f1  )
    

    it's not necessary to use cut. You can do this:

    usep=$(echo $output | awk -F% '{ print $1}' )
    
    0 讨论(0)
提交回复
热议问题