linux - 优化 Bash 脚本,移除 subshel​​l

标签 linux bash optimization

我有一个 bash 脚本,它列出了一个端口上连接的 IP 地址数量。我的问题是,如果有大量连接,它会像便便一样慢。我认为这是因为使用了子外壳,但我无法在不破坏脚本其余部分的情况下删除它们。这是完整的脚本,因为它相当短:

    #!/bin/bash

    portnumber=80
    reversedns_enabled=0

    [ ! -z "${1}" ] && portnumber=${1}
    [ ! -z "${2}" ] && reversedns_enabled=${2}

    #this will hold all of our ip addresses extracted from netstat
    ipaddresses=""

    #get all of our connected ip addresses
    while read line; do
            ipaddress=$( echo ${line} | cut -d' ' -f5 | sed s/:[^:]*$// )
            ipaddresses="${ipaddresses}${ipaddress}\n"
    done < <( netstat -ano | grep -v unix | grep ESTABLISHED | grep \:${portnumber} )

    #remove trailing newline
    ipaddresses=${ipaddresses%%??}

    #output of program
    finaloutput=""

    #get our ip addresses sorted, uniq counted, and reverse sorted based on amount of uniq
    while read line; do
            if [[ ${reversedns_enabled} -eq 1 ]]; then
                    reversednsname=""       

                    #we use justipaddress to do our nslookup(remove the count of uniq)
                    justipaddress=$( echo ${line} | cut -d' ' -f2 )
                    reversednsstring=$( host ${justipaddress} )
                    if echo "${reversednsstring}" | grep -q "domain name pointer"; then
                            reversednsname=$( echo ${reversednsstring} | grep -o "pointer .*" | cut -d' ' -f2 )
                    else
                            reversednsname="reverse-dns-not-found"
                    fi

                    finaloutput="${finaloutput}${line} ${reversednsname}\n"
            else
                    finaloutput="${finaloutput}${line}\n"
            fi
    done < <( echo -e ${ipaddresses} | uniq -c | sort -r )

    #tabulate that sheet son
    echo -e ${finaloutput} | column -t

大部分时间都花在了这个操作上:echo ${line} |剪切-d''-f5 | sed s/:[^:]*$// 内联它以生成更快的脚本的最佳方法是什么。 1000 个并发用户需要超过一秒的时间(这是我的基本目标,尽管应该能够在不耗尽我所有 cpu 的情况下处理更多)。

最佳答案

您可以使用 cut -d' ' <<< "$line" | sed ... 来减少它.你可以写一个更复杂的 sed脚本并避免使用 cut .

但真正的好处是避免循环,所以只有一个 sed (或 awkperl 或……)涉及脚本。我可能希望将其减少到 ipaddresses=$(netstat -ano | awk '...')所以不是 3 grep进程,加一 cutsed每行,只有一个 awk过程。

ipaddresses=$(netstat -ano |
              awk " /unix/           { next }  # grep -v unix
                   !/ESTABLISHED/    { next }  # grep ESTABLISHED
                   !/:${portnumber}/ { next }  # grep :${portnum}  "'
                                     { sub(/:[^:]*$/, "", $5); print $5; }'
             )

这可能相当笨拙,但它是对现有代码的相当直接的音译。注意报价以获得${portnumber}进入正则表达式。

由于您将 IP 地址列表输入 uniq -csort -r .你可能应该使用 sort -rn , 你可以使用 awkuniq -c ,也是。

唯一不能轻易改进的是 host ;这似乎一次只接受一个主机或 IP 地址参数,因此您必须为每个名称或地址运行它。

关于linux - 优化 Bash 脚本,移除 subshel​​l,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/21083851/

相关文章:

linux - Samba 导致 "mount:/is busy"

algorithm - 算法时间复杂度总是 O(1) 优于 O(n)?

bash - 如何使用 GNU parallel 并行运行 curl 命令

linux - 简单的 bash 脚本,我怎样才能让它更短更好?

MySQL优化需要解释

python - 更有效的方法来做到这一点

linux - 如何在 Linux 中创建不可读的文件

linux - 从函数 bashrc 调用 nohup 时删除输出

c++ - QT 5.10.1 Serial-Port 不发送,为什么?

linux - 比较文本文件中列出的文件