管道中变量的范围

时间:2009-11-24 12:22:55

标签: shell pipe

如果使用率超过10%,以下shell脚本将检查磁盘空间并将变量diskfull更改为1 最后一个回显始终显示0 我在if子句中尝试了global diskfull=1,但它没有用。 如果消耗的磁盘超过10%,如何将变量更改为1

#!/bin/sh
diskfull=0

ALERT=10
df -HP | grep -vE '^Filesystem|tmpfs|cdrom' | awk '{ print $5 " " $1 }' | while read output;
do
  #echo $output
  usep=$(echo $output | awk '{ print $1}' | cut -d'%' -f1  )
  partition=$(echo $output | awk '{ print $2 }' )
  if [ $usep -ge $ALERT ]; then
     diskfull=1
     exit
  fi
done

echo $diskfull

7 个答案:

答案 0 :(得分:5)

这是在管道中使用while的副作用。有两种解决方法:

1)将while循环及其使用的所有变量放在一个单独的范围内,如levislevis86所示

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

2)如果您的shell允许,使用进程替换,您可以将管道的输出重定向到while循环的输入

while read line; do
    foo=$( some calculation )}
done < <(some | complicated | pipeline)
do_something_with $foo

答案 1 :(得分:1)

使用管道时,外壳接缝使用子外壳来完成工作。由于这些子壳不知道$diskfull,因此值永远不会改变。

请参阅: http://www.nucleardonkey.net/blog/2007/08/variable_scope_in_bash.html

我按如下方式修改了你的脚本。它适用于我,也应该适用于您的系统。

#!/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

答案 2 :(得分:1)

@OP,使用外支撑或()

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" 
}

答案 3 :(得分:0)

我认为你不能进入diskfull=1行,因为如果你是,你根本就没有输出 - 下面的exit行会退出脚本。

我不知道为什么这不起作用,但请注意awk可以处理剩下的工作:

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

这样你就不需要while循环了。

答案 4 :(得分:0)

你可以用gawk这样做(不需要使用grep)。对于警报,您可以向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 

或检查是否有“msg”或不首先

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

答案 5 :(得分:0)

在这一行:

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

没有必要使用cut。你可以这样做:

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

答案 6 :(得分:0)

为了处理bash循环中的变量作用域问题,可以将变量保存在一个临时文件中,然后cat将其保存到变量中。这不是最聪明、最有效的解决方案,但它易于阅读和思考。

如果有人想尝试与 Glenn 的 solution 不同的东西,可以试试这个:

some | complicated | pipeline | {
while read line; do
    foo=$( some calculation )
done
do_something_with $foo

echo $foo > foo.tmp
}

# $foo not available here
foo=$(cat foo.tmp)
# $foo available here. do anything with it
rm foo.tmp

请注意,仅当您有权限创建文件(或指定您有权限的目录的绝对路径)时才有效