bash

时间:2017-05-31 08:02:21

标签: regex bash

我想知道是否可以多次匹配一个模式(匹配的数量不知道)并提取每个出现的数据进行比较?

我的目标是查找是否在接口上配置了vlan。

我有这个文件样本(我有截断它):

interface Ethernet1/16
  shutdown
  switchport access vlan 777
  spanning-tree bpduguard enable

interface Ethernet1/17
  switchport mode trunk
  switchport trunk native vlan 201
  switchport trunk allowed vlan 1-69,71-100,110-111,120,153,198,200-366,368-397,400-599,1000-3967,4048-4093
  channel-group 2 mode active

interface Ethernet1/18
  switchport mode trunk
  switchport trunk native vlan 201
  switchport trunk allowed vlan 1-69,71-100,110-111,120,153,198,200-366,368-397,400-599,1000-3967,4048-4093
  channel-group 2 mode active

interface Ethernet1/19
  switchport mode trunk
  switchport trunk native vlan 201
  switchport trunk allowed vlan 1-69,71-100,110-111,120,153,198,368-397,400-599,1000-3967,4048-4093
  channel-group 2 mode active

我有这个代码用于解析文件和每个接口,我检查是否可以找到范围内的vlan(在参数中提供)。

REGEX="^interface (.*)"
REGEX_TRUNKRANGEVLAN="^switchport trunk allowed.*(\d+)-(\d+),*"
vlan=$2  

while read line; do

  if [[ $line =~ $REGEX ]]; then      
    ifname=${BASH_REMATCH[1]}
  else
    if [[ $line =~ $REGEX_TRUNKRANGEVLAN ]]; then
        #for each pattern match on this line, I need to check
        if [ ${BASH_REMATCH[1]} -lt $vlan ] && [ ${BASH_REMATCH[2]} -gt $vlan ]; then
          echo "vlan is included in interface $ifname"
        fi
    fi
  fi
done <$1

例如,如果我查找vlan 250,输出将为:

  

vlan包含在接口Ethernet1 / 17中   vlan包含在接口Ethernet1 / 18

4 个答案:

答案 0 :(得分:1)

您需要提取所有范围并逐一进行测试。无需使用正则表达式模式提取它们,您可以使用IFS拆分行。凭借糟糕的bash功能:

$a=array(1,10,25,50);
rsort($a);
$number=15;
echo $number . " = "; 
$final = [];
foreach($a as $num) {
    if((int)($number / $num) > 0) {
        $final = array_merge($final, array_fill(0, (int)($number / $num), $num));
        $number -= (int)($number / $num) * $num;
    }
}
echo implode(' + ', $final);

答案 1 :(得分:1)

我认为这会奏效:

REGEX="^interface (.*)"
REGEX_TRUNKRANGEVLAN="^[ ]*switchport trunk allowed vlan (.*)"
vlan=$2

while read line
do
  if [[ $line =~ $REGEX ]]
  then
    ifname=${BASH_REMATCH[1]}
  fi

  if [[ $line =~ $REGEX_TRUNKRANGEVLAN ]]
  then
      old=$IFS
      IFS=","
      for range in ${BASH_REMATCH[1]}
      do
        if [[ $vlan -ge ${range%-*} && $vlan -le ${range#*-} ]]
        then
          echo "vlan is included in interface $ifname"
        fi
      done
      IFS=$old
  fi
done < $1

答案 2 :(得分:0)

我这样做了:

 class Model_Search extends ORM
    {
        protected $_has_many = array(
           'mp3s'       => array(
                        'model' => 'Mp3',
                        'through' => 'searches_mp3s',

                        ),
            );

答案 3 :(得分:0)

显然不是最漂亮的方式,当然也不是最有效的方式,但因为我花了一些时间编写这个命令,即使问题解决了,我也会分享它:

sed -r -e ':a' -e 'N' -e '$!ba' -e 's/\n//g' -e 's/(interface Ethernet)/\n\1/g' |awk '{gsub(",", " ", $15); print "echo "$1"_"$2" "$15}' | sed -r 's#([0-9]*)-([0-9]*)#`seq \1 \2`#ge'

它的作用是将所有接口块转换为一行<interface> <ranges>并转换vlan列表中每一行的所有范围。

即。如果该行是:<interface> 3-5 7 8-10 它将转变为:<interface> 3 4 5 7 8 9 10

  • -e ':a' -e 'N' -e '$!ba' -e 's/\n//g':删除所有\n
  • -e 's/(interface Ethernet)/\n\1/g':每个interface Ethernet都将成为新行的开头
  • awk '{gsub(",", " ", $15); print "echo "$1"_"$2" "$15}':将","替换为" "并打印interface Ethernet...和范围字段。这里的诀窍是echo将在下一个sed语句中使用
  • sed -r 's#([0-9]*)-([0-9]*)# seq \ 1 \ 2 #ge':将vlan范围的每个模式XXX-XXX替换为:seq XXX XXX。然后e标志将执行替换行。

    将采用以下形式:

echo interface `seq 3 5` 7 `seq 8 10`

之后你只需要grep出现vlan的行。

我认为现在对你没什么用处,但是我花了太多时间在这个上面分享它;)

- 编辑

一些awk脚本更加精致:

awk '/interface Ethernet[0-9]*\/[0-9]*/{iface=$1" "$2}; /switchport trunk allowed vlan/{ gsub(",", " "); print "echo "iface" \\" ; for(i = 5; i<=NF; i++) { if ($i~/[0-9]*-[0-9]*/) { gsub("-", " ", $i); printf (" `seq %s`", $i) } else { printf (" %s",$i) } ; if (i!=NF){print "\\"} else {print""} } }' /tmp/test.vlan | sh |grep ' 250 ' |cut -d" " -f1,2