提高使用循环,awk和剪切的BASH脚本的性能

时间:2012-01-13 10:01:59

标签: bash awk

这是一个来自bash脚本中间的片段,我们用它来监视服务器上的挂载状态:

OIFS=$IFS
IFS=$'\n'
for mount in $mounts; do
        mountcount=$(($mountcount+1))
        dev=`echo $mount | awk {'print $1'};`
        dir=`echo $mount | awk {'print $2'};`
        opts=`echo $mount | awk {'print $4'};`
        state=`echo $opts | cut -d ',' -f 1`
        if [ "$state" = "ro" ]; then
                crit="true"
                break
        fi
done
IFS=$IFS

$ mounts的内容类似于:

rootfs / rootfs rw 0 0
none /sys sysfs rw,nosuid,nodev,noexec,relatime 0 0
none /proc proc rw,nosuid,nodev,noexec,relatime 0 0
none /dev devtmpfs rw,relatime,size=1028136k,nr_inodes=218146,mode=755 0 0
none /dev/pts devpts rw,nosuid,noexec,relatime,gid=5,mode=620,ptmxmode=000 0 0
fusectl /sys/fs/fuse/connections fusectl rw,relatime 0 0
/dev/disk/by-uuid/f2337686-ec8d-429a-9002-592c564ddbf3 / ext3 rw,relatime,errors=remount-ro,barrier=0,data=ordered 0 0
none /sys/kernel/debug debugfs rw,relatime 0 0
none /sys/kernel/security securityfs rw,relatime 0 0
none /dev/shm tmpfs rw,nosuid,nodev,relatime 0 0
none /var/run tmpfs rw,nosuid,relatime,mode=755 0 0
none /var/lock tmpfs rw,nosuid,nodev,noexec,relatime 0 0

正如您应该能够看到的那样,我正在解析将每一行拆分为它的组件,以查找以只读方式挂载的挂载。从功能上来说这绝对没问题,但问题是我们在100多台服务器上运行它,目前用上述数据运行上述循环需要一秒钟(有时)。

我认为这个问题是由执行awkcut时等待引起的,因为它们是外部程序,因此我想知道是否有更高效的方法可以实现相同的功能。我不太了解bash,因为他们知道可以帮助解决这个问题的内部功能,或者在awk中足够熟练地将其作为一行来完成。

我的感觉是awk的3个电话和cut的1个电话都可以在awk的1行中完成。任何帮助非常感谢!

修改

稍后在脚本中使用变量dev,dir和mountcount来构建输出。

修改

我已将脚本更改为以下内容:(所有回声都在那里作为测试)

mountcount=0

OIFS=$IFS
IFS=$'\n'
for mount in $mounts; do
    mountcount=$(($mountcount+1))
    echo $mount
    echo $mount | read dev dir fs opts
    echo $dev
    echo $dir
    echo $fs
    echo $opts
    state=`echo $opts | cut -d ',' -f 1`
    if [ "$state" = "ro" ]; then
        crit="true"
        break
    fi
done
IFS=$OIFS

这给了我以下内容:

rootfs / rootfs rw 0 0




fusectl /sys/fs/fuse/connections fusectl rw,relatime 0 0




/dev/disk/by-uuid/1be5b3ae-8239-4177-9af6-22ad0afa662a / ext3 rw,relatime,errors=remount-ro,data=ordered 0 0




/dev/disk/by-uuid/1be5b3ae-8239-4177-9af6-22ad0afa662a /dev/.static/dev ext3 rw,relatime,errors=remount-ro,data=ordered 0 0




devpts /dev/pts devpts rw,relatime 0 0




securityfs /sys/kernel/security securityfs rw,relatime 0 0

所以read没有按预期工作。

4 个答案:

答案 0 :(得分:6)

这可能对您有用:

OIFS=$IFS; IFS=$'\n'; ma=($mounts); IFS=$OIFS
mountcount=0
for mount in "${ma[@]}"; do
    ((mountcount++))
    fa=($mount)
    dev=${fa[0]}
    dir=${fa[1]}
    opts=${fa[3]}
    state=${fa[3]/,*}
    if [ "$state" = "ro" ]; then
            crit="true"
            break
    fi
done

答案 1 :(得分:0)

可能像

read dev dir fs opts <<<"$mount"

首发?

或者整个事情看起来非常像

read dev dir fs opts <<<"$(grep ' ro,' <<<"$mounts"|head -n 1)"

如果有一个关键线,它将为​​你提供关键线(对于grep来说可能更精细的表达式会很好)。在这种情况下,不计数。

P.S。在最后一行IFS=$IFS,我相信你的意思是IFS=$OIFS

答案 2 :(得分:0)

反转逻辑怎么样?在开始时运行awk 3次,cut运行一次,将结果存储到数组$devs, $dirs, $optses, $states。然后,在for ((i=0; i<max; i++))循环中,获取${devs[i]}等等,然后对它们执行任务。

答案 3 :(得分:0)

也许你在这里缩写了你的剧本,其中的内容比我能看到的要多。但你为什么不这样做呢?

echo "$mounts" | grep -w 'ro'

获取所有只读挂载的列表,或者,如果您只想要第一个挂载,

echo "$mounts" | grep -w 'ro' | head -1

你仍然可以使用awk处理这个输出,但是awk的功能要少得多,它的运行速度要快得多。

'ro'与-w一起应该足够独特,但如果你得到误报,你可以使用egrep更复杂的模式。