Bash脚本超级慢

时间:2015-01-23 20:35:37

标签: performance bash

我正在更新旧脚本以解析ARP数据并从中获取有用信息。我们添加了一个新路由器,虽然我可以将ARP数据从路由器中拉出来,但它是一种新的格式。我有一个文件" zTempMonth"这是来自两组路由器的所有arp数据,我需要将其编译成一个标准化的新数据格式。下面的代码行按逻辑方式执行我需要它们 - 但它非常慢 - 因为在以前脚本需要20-30分钟的情况下运行这些循环将花费数天时间。有没有办法加快速度,或者找出减慢速度的方法?

提前谢谢你,

    echo "Parsing zTempMonth"
    while read LINE
    do
            wc=`echo $LINE | wc -w`
            if [[ $wc -eq "6" ]]; then
                    true
                    out=$(echo $LINE | awk '{ print $2 " " $4 " " $6}')
                    echo $out >> zTempMonth.tmp

            else
                    false
            fi

            if [[ $wc -eq "4" ]]; then
                    true
                    out=$(echo $LINE | awk '{ print $1 " " $3 " " $4}')
                    echo $out >> zTempMonth.tmp
            else
                    false
            fi


    done < zTempMonth

2 个答案:

答案 0 :(得分:6)

  1. 虽然读取循环很慢。
  2. 循环中的子shell很慢。
  3. >>open(f, 'a'))循环调用很慢。
  4. 你可以加快速度,保持纯粹的狂欢,只是失去#2和#3:

    #!/usr/bin/env bash
    
    while read -a line; do
        case "${#line[@]}" in
            6) printf '%s %s %s\n' "${line[1]}" "${line[3]}" "${line[5]}";;
            4) printf '%s %s %s\n' "${line[0]}" "${line[2]}" "${line[3]}";;
        esac
    done < zTempMonth >> zTempMonth.tmp
    

    但如果有多行,这仍然比纯awk慢。考虑一个简单的awk脚本:

    BEGIN {
        print "Parsing zTempMonth"
    }   
    
    NF == 6 {
        print $2 " " $4 " " $6
    }   
    
    NF == 4 {
        print $1 " " $3 " " $4
    }   
    

    你可以像这样执行:

    awk -f thatAwkScript zTempMonth >> zTempMonth.tmp
    

    获得与当前脚本相同的附加方法。

答案 1 :(得分:2)

编写shell脚本时,直接调用函数而不是使用子shell调用函数几乎总是更好。我见过的通常惯例是回显函数的返回值并使用子shell捕获该输出。例如:

#!/bin/bash
function get_path() {
    echo "/path/to/something"
}
mypath="$(get_path)"

这很好用,但使用子shell有很大的速度开销,而且有更快的替代方案。相反,你可以只有一个约定,其中一个特定的变量总是函数的返回值(我使用retval)。这还有一个额外的好处,也允许您从函数中返回数组。

如果您不知道子shell是什么,为了本博客文章的目的,子shell是另一个bash shell,无论何时使用$()或``生成并用于执行您放置的代码内部。

我做了一些简单的测试,让你观察开销。对于两个功能相同的脚本:

这个使用子shell:

#!/bin/bash
function a() {
    echo hello
}
for (( i = 0; i < 10000; i++ )); do
    echo "$(a)"
done

这个使用变量:

#!/bin/bash
function a() {
    retval="hello"
}
for (( i = 0; i < 10000; i++ )); do
    a
    echo "$retval"
done

这两者之间的速度差异显着且显着。

$ for i in variable subshell; do
> echo -e "\n$i"; time ./$i > /dev/null
> done

variable

real 0m0.367s
user 0m0.346s
sys 0m0.015s

subshell

real 0m11.937s
user 0m3.121s
sys 0m0.359s

如您所见,使用variable时,执行需要0.367秒。但是,子shell需要整整11.937秒!

来源:http://rus.har.mn/blog/2010-07-05/subshells/