0

我有一个大约 3000 个 IP 地址的列表,这些 IP 地址是 pdsh 输出的结果,通过管道dshback -c将输出格式化为可读格式。我喜欢 的可读性dshback -c,但我遇到的问题是具有公共八位字节的 IP 被折叠以节省空间。我需要为我的项目的其余部分提供完整的 IP 地址。

有没有一种简单的方法来转换这个输入:

192.168.38.[217,222],192.168.40.215,192.168.41.[219-222]

到这个输出:

192.168.38.217,192.168.38.222,192.168.40.215,192.168.41.219,192.168.41.220,192.168.41.221,192.168.41.222

我在想 sed 可以直接使用,但我不确定如何将公共八位字节存储在变量中。出于这个原因,我相信 bash 脚本需要与 sed 一起使用。任何帮助或正确方向的观点将不胜感激。

4

4 回答 4

1

如果您可以更改输入,则可以使用以下表格:

echo 192.168.38.{217,222} 192.168.40.215 192.168.41.{219..222} | tr ' ' ','

否则你可以通过 command 和 eval 来改变它:

eval echo $( echo '192.168.38.[217,222],192.168.40.215,192.168.41.[219-222]' | \
 sed 's/,/ /g;s/\[/{/g;s/]/}/g;s/-/../g;s/\({[0-9]\+\) \([0-9]\+}\)/\1,\2/g' | \
 grep -v '[^0-9{}., ]' ) | tr ' ' ','

请注意, eval 对无效数据非常危险,因此我grep '[^0-9{}., ]'用来排除任何意外符号。 sed在这个命令中,只是将您的原始字符串转换为我上面提到的形式。

于 2013-08-07T05:23:44.377 回答
0

如果你准备好使用 awk 那么你可以试试这个

echo "192.168.38.[217,222],192.168.40.215,192.168.41.[219-222]" |sed 's/\[//g' | sed 's/\]//g' | awk -F, '{for(i=1;i<=NF;i++){n=split($i,a,".");IPL="";if(n>1){PIP=a[1] "." a[2] "." a[3];}else{IPL=PIP "." $i;}if(index(a[4],"-") > 0){x=0;split(a[4],b,"-");for(j=b[1];j<=b[2];j++){if(x==0){IPL=PIP "." j;x++;}else{IPL=IPL "," PIP "." j;}}}else if(index(a[4],",") > 0){split(a[4],b,",");IPL=PIP "." b[1] "," PIP "." b[2];}else{if(length(IPL)<=3){IPL=PIP "." a[4];}}printf("%s,",IPL);}}'

如果您有兴趣使用它,我可以解释逻辑...

于 2013-08-07T06:08:48.913 回答
0

这是根据需要纯粹使用 Bash 处理它的一种方法。没有 awks、sed 和其他东西。

#!/bin/bash

shopt -s extglob
IFS=,

while read -r LINE; do
    OUTPUT=()
    while [[ -n $LINE ]]; do
        case "$LINE" in
        +([[:digit:]]).+([[:digit:]]).+([[:digit:]]).+([[:digit:]]))
            OUTPUT[${#OUTPUT[@]}]=$LINE
            break
            ;;
        +([[:digit:]]).+([[:digit:]]).+([[:digit:]]).+([[:digit:]]),*)
            OUTPUT[${#OUTPUT[@]}]=${LINE%%,*}
            LINE=${LINE#*,}
            ;;
        +([[:digit:]]).+([[:digit:]]).+([[:digit:]]).\[+([[:digit:],-])\]*)
            SET=${LINE%%\]*}
            PREFIX=${SET%%\[*}
            read -a RANGES <<< "${SET:${#PREFIX} + 1}"
            for R in "${RANGES[@]}"; do
                case "$R" in
                +([[:digit:]]))
                    OUTPUT[${#OUTPUT[@]}]=${PREFIX}${R}
                    ;;
                +([[:digit:]])-+([[:digit:]]))
                    X=${R%%-*} Y=${R##*-}
                    if [[ X -le Y ]]; then
                        for (( I = X; I <= Y; ++I )); do
                            OUTPUT[${#OUTPUT[@]}]=${PREFIX}${I}
                        done
                    else
                        for (( I = X; I >= Y; --I )); do
                            OUTPUT[${#OUTPUT[@]}]=${PREFIX}${I}
                        done
                    fi
                    ;;
                esac
            done
            LINE=${LINE:${#SET} + 2}
            ;;
        *)
            # echo "Invalid token: $LINE" >&2
            break
        esac
    done
    echo "${OUTPUT[*]}"
done

对于输入

192.168.38.[217,222],192.168.40.215,192.168.41.[219-222]

运行 bash temp.sh < temp.txt 产生

192.168.38.217,192.168.38.222,192.168.40.215,192.168.41.219,192.168.41.220,192.168.41.221,192.168.41.222

它也与范围一致。如果 X 晚于 Y,例如 200-100,那么它将生成 IPS,其子集为 200 到 100。该脚本还可以处理多行输入。

它还应该适用于 [100,200-250] 等混合范围。

于 2013-08-07T06:15:12.430 回答
0

使用 GNU awk:

$ cat tst.awk
BEGIN{ FS=OFS="," }
{
    $0 = gensub(/(\[[[:digit:]]+),([[:digit:]]+\])/,"\\1+\\2","g")
    gsub(/[][]/,"")

    for (i=1;i<=NF;i++) {
        split($i,a,/\./)
        base  = a[1] "." a[2] "." a[3]
        range = a[4]
        split(range,r,/[+-]/)

        printf (i>1 ? "," : "")
        if (range ~ /+/) {
            printf "%s.%s", base, r[1]
            printf "%s.%s", base, r[2]
        }
        else if (range ~ /-/) {
            for (j=r[1]; j<=r[2]; j++) {
                printf "%s.%s", base, j
            }
        }
        else {
            printf "%s.%s", base, range
        }
    }
    print ""
}
$
$ awk -f tst.awk file
192.168.38.217192.168.38.222,192.168.40.215,192.168.41.219192.168.41.220192.168.41.221192.168.41.222

我们需要 gensub() 将方括号内的逗号更改为不同的字符 ( +),以便我们可以使用括号外的逗号作为字段分隔符,并且 gensub() 使其特定于 gawk。

于 2013-08-07T13:26:30.040 回答