管道中变量的范围

发布于 2024-08-12 06:01:01 字数 563 浏览 3 评论 0原文

以下 shell 脚本将检查磁盘空间,如果使用率超过 10%,则将变量 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

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 0
I tried the global diskfull=1 in the if clause but it did not work.
How do I change the variable to 1 if the disk consumed is more than 10%?

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

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(7

長街聽風 2024-08-19 06:01:02

这是在管道中使用 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

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
桃扇骨 2024-08-19 06:01:02

当使用管道时,外壳似乎使用子外壳来完成工作。由于这些子 shell 不知道 $diskfull,因此该值永远不会更改。

看:
https://gist.github.com/CMCDragonkai/0a66ba5e37c5d1746d8bc814b37d6e1d

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

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

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

See:
https://gist.github.com/CMCDragonkai/0a66ba5e37c5d1746d8bc814b37d6e1d

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
少跟Wǒ拽 2024-08-19 06:01:02

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

@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" 
}
最终幸福 2024-08-19 06:01:02

我认为您一定不会到达 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 循环。

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.

幻梦 2024-08-19 06:01:02

你可以用 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

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
缘字诀 2024-08-19 06:01:02

在这一行中:

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

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

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

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}' )
很酷又爱笑 2024-08-19 06:01:02

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

如果有人想尝试与 Glenn 不同的解决方案,可以尝试以下操作:

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

请注意,只有在您拥有权限的情况下才有效创建文件(或指定您有权限的目录的绝对路径)

To deal with variable scope problem in bash loop, one can save the variable in a temporary file and later cat it to variable. It's not the smartest and efficient solution but It's easy to read and think.

If someone want to try something different than Glenn's solution, it can try this:

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

Please note, It's only valid if you have permission to create a file (or specify the absolute path to directory where you have permission)

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文