Bash 脚本超级慢

问题描述 投票:0回答:2

我正在更新一个旧脚本来解析 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
performance bash
2个回答
10
投票
  1. 虽然读取循环很慢。
  2. 循环中的子 shell 速度很慢。
  3. >>
    (
    open(f, 'a')
    ) 循环调用速度很慢。

你可以加快速度并保持纯粹的bash,只需失去#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

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


8
投票

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

例如:

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

mypath="$(get_path)"

这工作得很好,但是使用子 shell 会带来显着的速度开销,并且有一个更快的替代方案。相反,您可以采用约定,其中特定变量始终是函数的返回值(我使用

retval
)。这样做的另一个好处是还允许您从函数返回数组。

如果您不知道子 shell 是什么,就本博文而言,子 shell 是另一个 bash shell,每当您使用

$()
``
时都会生成它,并用于执行您放入其中的代码。

我做了一些简单的测试,以便您观察开销。对于两个功能等效的脚本:

这个使用了

subshell

#!/bin/bash

function foo() {
  # Return value
  echo hello
}

for (( i = 0; i < 10000; i++ )); do
  result="$(foo)"
  echo $result
done

这个使用了

variable

#!/bin/bash

# Initialize
retval=""

function foo() {
  # Return value
  retval="hello"
}

for (( i = 0; i < 10000; i++ )); do
  foo
  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
subshell
是可执行脚本)

如您所见,使用

variable
时,执行需要 0.367 秒。
subshell
然而需要整整 11.937 秒!

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

© www.soinside.com 2019 - 2024. All rights reserved.