如何处理多个范围和单个数字的解析?

时间:2019-07-19 16:43:42

标签: bash

我正在尝试采用这样的值:

test2.sh switchname unicast [IgnorePort]

IgnorePort下方有范围,例如1-8,12,34,37-43 或类似的任何变化。我将如何处理这种解析为数组或单个值的解析

我一直在搜索它,却找不到任何东西,尽管我觉得这是每个人在某个时间点都必须学习的东西。

当前必须要做的事情:

test2.sh switchname unicast 1
test2.sh switchname unicast 2
test2.sh switchname unicast 3
test2.sh switchname unicast 10

想做的事

test2.sh switchname unicast 1-3,10

3 个答案:

答案 0 :(得分:2)

要将该范围的数字转换为列表,请尝试:

awk -F- -v RS=, '{print $1} NF==2{for (i=$1+1;i<=$2;i++)print i}'

例如:

$ echo 1-3,5,9-10 | awk -F- -v RS=, '{print $1} NF==2{for (i=$1+1;i<=$2;i++)print i}'
1
2
3
5
9
10

或者,要在脚本中使用:

$ cat script
#!/bin/bash
for i in $(echo "$3" | awk -F- -v RS=, '{print $1} NF==2{for (i=$1+1;i<=$2;i++)print i}')
do
    echo "Working on $i"
done

作为运行上述脚本的示例:

$ bash script switchname unicast 1-2,11,20-21
Working on 1
Working on 2
Working on 11
Working on 20
Working on 21

工作原理

awk一次读取一条记录。每个记录都分为几个字段。在我们的例子中,我们将,视为记录分隔符。因此,例如在读入1-3,5,9-10时,awk看到的第一个记录为1-3,并且该记录具有两个字段13。第二个记录是5,依此类推。每条记录依次处理。

  • -F-

    这告诉awk使用-作为字段分隔符

  • -v RS=,

    这告诉awk使用,作为记录分隔符。

  • print $1

    这告诉awk打印第一个字段。

  • NF==2{for (i=$1+1;i<=$2;i++)print i}

    如果记录中有两个字段,则打印其余数字。

答案 1 :(得分:0)

最简单的方法是接受单个数字列表,而不是您必须解析的范围。 bash可以通过括号扩展轻松地为您生成单个数字。

#! /bin/bash
# Sketch of your script test2.sh when accepting arbitrary many individual numbers

switchname="$1"
unicast="$2"
shift 2
ports=("$@")

# do something, for instance ...
for port in "${ports[@]}"; do
    # something
done

然后按如下所示调用您的脚本以模拟范围1-8,12,34,37-43

test2.sh switchname unicast {{1..8},12,34,{37..43}}

如果您真的想指定范围,那么下一个更简单的操作就是将范围转换为大括号模式,然后eval将其转换为大括号模式。请记住,如果您弄乱了输入验证,可能会导致代码注入。

#! /bin/bash
# Sketch of your script test2.sh when accepting one range

switchname="$1"
unicast="$2"
range="$3"
if ! [[ range =~ ^[0-9]+(-[0-9]+)?(,[0-9]+(-[0-9]+)?)*$ ]]; then
    echo "Illegal range expression: $range"
    exit 1
fi
bracePattern="{$(sed -E 's/([^,]+)-([^,]+)/{\1..\2}/g' <<< "$range")}"
eval "ports=($bracePattern)"

# do something, just like in the first version of the script

答案 2 :(得分:0)

以下功能将回显范围内的每个数字

function ranger {
        A=$(echo $1 | tr "," " ")
        for a in $A
        do
                if [[ $a == *"-"* ]]; then
                        B=( $(echo $a | tr "-" " ") )
                        x=${B[0]}
                        y=${B[1]}
                        for z in $(seq ${B[0]} ${B[1]})
                        do
                                echo $z
                        done
                else
                        echo $a
                fi
        done
}

因此,修改test2.sh与此类似

function test2 {
    for i in $(ranger $3)
    do
        #execute test2.sh code
    done
}

然后运行 $ test2.sh switchname unicast 1,2,5-7