【问题标题】:Sorting information and processing output with variables in Bash在 Bash 中使用变量对信息进行排序和处理输出
【发布时间】:2019-02-04 14:23:52
【问题描述】:

过去我收到了一些有用的回复,希望大家能帮助我。我遇到了一些我无法确定的奇怪行为。我正在处理 Cisco 交换机的配置文件,并希望生成列出 VLAN IP 地址的输出,格式如下:

Vlan1:172.31.200.1 255.255.255.0

Vlan10:172.40.220.1 255.255.255.0

“Vlan”将被捕获在一个变量中,IP/掩码是使用“sed”提取的,它在大多数情况下都有效。有时它会拒绝填充“vlan”变量,尽管它看起来对其他配置很有效。

如果只有一个 VLAN,它只会处理那个 VLAN,如果有多个 VLAN,它会处理额外的 VLAN。如果用户选择 (-v) 它在列表中包括 VLAN1,则配置了多个 VLAN(否则它会忽略 VLAN1)。

此输入文件出现损坏(文件名 1.cfg):

!
interface Vlan1
 ip address 172.29.96.100 255.255.255.0
!
ip default-gateway 172.29.96.1
ip http server
no ip http secure-server
!

这个输入文件可以正常工作(文件名 2.cfg):

!
interface Vlan1
 ip address 172.31.200.111 255.255.255.0
 no ip route-cache
!
ip default-gateway 172.31.200.1
ip http server
ip http secure-server

我得到的输出是这样的:

注意第一个没有包含“Vlan1”引用?

这是我的脚本:

#!/bin/bash

if [ -f getlan.log ];
then
    rm getlan.log
fi

TempFile=getlan.log
verbose=0

while [[ $# -gt 0 ]]
do
key="$1"

case $key in
    -v)
    verbose=1
    shift
    ;;
    #*)
    #exit
    #shift
    #;;
esac
done

#Start Processing all files
files=$( ls net )
for i in $files; do

    #########################################################
    # Collect Configured VLAN Interfaces and IP Information #
    #########################################################

    echo "--------  Configured VLAN Interfaces  --------" >> ~/$TempFile
    echo "" >> ~/$TempFile

    if [ `grep "^interface Vlan" ~/net/$i | awk '{ print $2 }' | wc -l` -gt 1 ];
    then
        for g in `grep "^interface Vlan" ~/net/$i | awk '{ print $2 }'`;
        do
            if [ $g == "Vlan1" ];
            then
                if [ $verbose -gt 0 ];
                then
                    echo "$g": `sed -n '/^interface '$g'/,/!/p' ~/net/$i | head -n 5 | grep -i "ip address" | awk '{ print $3, $4 }'` >> ~/$TempFile
                fi  
            else
                echo "$g": `sed -n '/^interface '$g'/,/^!/p' ~/net/$i | grep -i "ip address" | awk '{ print $3, $4 }'` >> ~/$TempFile
            fi
        done
        echo "" >> ~/$TempFile
    else
        vlanid=`grep "^interface Vlan" ~/net/$i | awk '{ print $2 }'`
        echo $vlanid: `sed -n '/^interface 'Vlan'/,/^!/p' ~/net/$i | grep -i "address" | awk '{ print $3, $4 }'` >> ~/$TempFile
        echo "" >> ~/$TempFile
    fi
done

如果这更一致,那就太好了。谢谢!

【问题讨论】:

  • 请在您的问题中添加示例输入和该示例输入所需的输出。
  • 示例包括两者...所需的输出是让行包括 Vlan(Vlan1、Vlan10 等),后跟 IP 和掩码。第二个例子是正确的。在第一种情况下,它只显示 IP/掩码。我的输入文件也显示在上面的原始描述中。
  • 一般情况下grep ... | awk '{foo}'可以换成awk '/.../ { foo }'。我通常也倾向于摆脱所有sed/head/awk/等。支持使用 BashFAQ #1 while read 循环来解析文件的杂项,这将更加高效和运行时间,并且附带的复杂性更少(移动部件更少)。
  • 考虑通过shellcheck.net 运行您的代码并修复它找到的内容。 bash 中的引用规则可能与您对其他语言的期望相反——例如,在[ "$g" = Vlan1 ] 中,它是需要引用的变量的扩展,以便您的代码在读取空字符串或其他异常文件时能够可靠地运行内容,不是常量字符串。

标签: bash variables sed scripting


【解决方案1】:

最佳实践方法可能看起来更像:

#!/usr/bin/env bash
interface_re='^[[:space:]]*interface[[:space:]]+(.*)'
ip_re='^[[:space:]]*ip address (.*)'

process_file() {
  local line interface

  interface=
  while IFS= read -r line; do
    if [[ $line =~ $interface_re ]]; then
      interface=${BASH_REMATCH[1]}
      continue
    fi
    if [[ $interface ]] && [[ $line =~ $ip_re ]]; then
      echo "${interface}: ${BASH_REMATCH[1]}"
    fi
  done
}

for file in net/*; do
  process_file <"$file"
done

这可以测试如下:

process_file <<'EOF'
!
interface Vlan1
 ip address 172.29.96.100 255.255.255.0
!
ip default-gateway 172.29.96.1
ip http server
no ip http secure-server
!
!
interface Vlan1
 ip address 172.31.200.111 255.255.255.0
 no ip route-cache
!
ip default-gateway 172.31.200.1
ip http server
ip http secure-server
EOF

...从两个interface 块中正确识别ip address 行,发出:

Vlan1: 172.29.96.100 255.255.255.0
Vlan1: 172.31.200.111 255.255.255.0

【讨论】:

  • 感谢您的意见,我确定我的编码不符合最佳实践规范,并且看到其他做事方式总是很好。我尝试了您的代码并收到了相同的结果。第一个条目仍然无法包含 Vlan 标识符。奇怪的是,使用我上面的代码并添加一个 echo 语句来回显它成功回显的 $vlanid,但是创建 vlan:ip 掩码的行仍然失败。这很奇怪,因为它表明它已成功设置变量。此外,它适用于其他实例。
  • 使用set -x 启用日志记录。如果输入中有隐藏字符,我不会感到惊讶。
  • 请记住,顺便说一句——你可以把我在这个答案中的代码带到ideone.com,看看它在那里工作。现在,我无法看到它在任何地方都失败了。如果你为这个问题构建了一个 MCVE,其他人可以使用它来查看代码失败而没有任何更改(不需要 mkdir net 并在其中创建文件,只需复制和粘贴——就像你可以复制和 -粘贴此答案,无需进行任何更改即可对其进行测试),这会带来很多好处。
  • 请参阅ideone.com/z7jq3o 了解此类工作示例。如果您单击fork 按钮并更改输入直到它失败,那么这样做会让某人处于更好的位置来帮助您。
  • 谢谢,这很有帮助。我也在浏览输入文件。我注意到偶尔会有额外的字符,这让我很伤心。 Perl 具有“chomp”功能,并且 Bash 中没有简单的等价物来删除隐藏的东西。在“vi”中有一个字符,但删除它似乎不会改变行为。启用“-x”确实确认这是我的问题。它将第一个“Vlan1”注册为“Vlan1\r”
猜你喜欢
  • 1970-01-01
  • 2021-05-04
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-06-04
  • 2020-03-01
  • 2018-01-30
相关资源
最近更新 更多