如果awk不存在,则跳过文件

时间:2017-11-07 11:40:31

标签: shell awk scripting zsh

我花了一些时间试图通过各种互联网搜索和挖掘stackoverflow来解决这个问题。我会尽力解释这个最好的菜鸟。

我有一个脚本,用于搜索配置存储库目录,该目录中填充了我们已部署的每个Juniper和Cisco路由器和交换机的目录。每个设备目录都有一两个我感兴趣的文件,“show.version”和“show.chassis.hardware”,除非它们没有。第二个文件“show.chassis.hardware”不是Cisco盒子所具有的命令,因此Cisco设备目录中不存在该文件。还有一个命名方案可以很容易地告诉我该设备是Juniper还是Cisco,这也是我的脚本存在的部分原因。

为了让事情变得更有趣,不同的模型甚至软件版本以不同的格式输出show.version文件(对于Cisco和Juniper),所以我的awk充满了我们将遇到的所有不同领域。

脚本:

#!/usr/local/bin/zsh
svn="$HOME/svn/nw_config_data/"

case "$1" in
("-a")
hosts=""
;;
("-b")
hosts=".bb.domain.net"
;;
("-c")
hosts=".cpe.domain.net"
;;
("-e")
hosts=".etech.domain.net"
;;
("-k")
hosts=".core.domain.net"
;;
("-m")
hosts=".maint.domain.net"
;;
("-o")
hosts=".ohgov.domain.net"
;;
esac

dirs=($(ls -d $svn*$hosts*))
for hostdir in $dirs
do host=$(echo $hostdir | grep -Eo "(\w|\.|-)*$")

awk -v h=$host '/^Model/{m=$2} /^Model number/{m=$4} /^\*0/{m=$2}
/^JUNOS Base OS boot/{v=$5} /^Junos:/{v="["$2"]"} /^BOOTLDR:/{v=$7} 
/^JUNOS EX  Software Suite/{v=$5} /^ROM:/{v=$5} /^JUNOS Software 
Release/{v=$4} /^Chassis/{s=$2} /^Motherboard serial number/{s=$3}
END {if(m!="number") {printf("%s %s %s %s\n",h,m,v,s)}}' 
"$hostdir/show.version" "$hostdir/show.chassis.hardware"
done

运行脚本时的样子:

% cver -b

device1-e0.bb.domain.net ex4300-24t [14.1X53-D25.2] Serial#
device2-e0.bb.domain.net ex4300-24t [14.1X53-D25.2] Serial#
awk: can't open file /home/clmbn eng2/a/rwalker/svn/nw_config_data/device3-e1.bb.domain.net/show.chassis.hardware
input record number 55, file /home/clmbn-eng2/a/rwalker/svn/nw_config_data/device3-e1.bb.domain.net/show.chassis.hardware
source line number 1
device4-r0.bb.domain.net m7i [13.3R6.5] Serial#
...

我希望它看起来像什么

% cver -b
device1-e0.bb.domain.net ex4300-24t [14.1X53-D25.2] Serial#
device2-e0.bb.domain.net ex4300-24t [14.1X53-D25.2] Serial#
device3-e1.bb.domain.net C3750 12.1(14r)EA1a, Serial#
device4-r0.bb.domain.net m7i [13.3R6.5] Serial#
...

我有13个目录没有“show.chassis.hardware”文件,但确实有“show.version”文件,它确实包含了我需要的所有信息。我有一个没有文件的目录,但没关系,因为该设备将被替换。

从我读过的内容来看,awk可能无法做到这一点,但我相信那里有人知道如何让它发挥作用。如果我的方法(shell和awk脚本)不能正常工作而我需要用别的东西(例如Perl或Python)来完成,我将完全陷入困境,直到我能够学到足够的东西来将我的脚本转换为其中一种语言。

此外,我们没有在此服务器上安装bash,因为我不是管理员,所以我不知道什么时候会这样做。

2 个答案:

答案 0 :(得分:2)

你需要

  

-f file

     

如果文件存在且为常规文件,则为true。

if [[ -f "$hostdir/show.version" && -f "$hostdir/show.chassis.hardware" ]]; then

      # your awk command goes here...
      awk '{  }' "$hostdir/show.version" "$hostdir/show.chassis.hardware"
else
      echo "not enough files found"             
fi

您可以参考:http://zsh.sourceforge.net/Doc/Release/Conditional-Expressions.html

- 编辑 -

  

这个脚本跳过没有的目录很酷   有文件,但它不会从中提取信息   无论如何,“show.version”文件并打印该信息。所以输出   显示device1,device2,device 4 ...

以下是代码段

function myfunc(){
   # replace with your awk
   awk '{ print }' "$@" 
}

if [[ -f "$hostdir/show.version" && -f "$hostdir/show.chassis.hardware" ]]; then

      # your awk command goes here...
      myfunc "$hostdir/show.version" "$hostdir/show.chassis.hardware"
else
      echo "not enough files found"

      # pass only one file, version file
      myfunc "$hostdir/show.version"           
fi

答案 1 :(得分:1)

你可以使用zsh' (...|...) globbing:

$ mkdir foo bar; touch {foo,bar}/show.version foo/show.chassis.hardware
$ echo foo/show.(version|chassis.hardware)
foo/show.chassis.hardware foo/show.version
$ echo bar/show.(version|chassis.hardware)
bar/show.version

由于这是通配的,它只会扩展到现有文件。所以你的awk命令看起来像:

awk -v h=$host '/^Model/{m=$2} ... END {...}' "$hostdir"/show.(version|chassis.hardware)

(省略awk脚本以提高可读性)

我还使用关联数组而不是案例来简化你的脚本:

#!/usr/local/bin/zsh

usage () {
    echo "Help!"   # echo your help message here
    exit $1
}

svn="$HOME/svn/nw_config_data/"

declare -A hosts # make associative array
hosts["-a"]=""
hosts["-b"]=".bb.domain.net"
hosts["-c"]=".cpe.domain.net"
hosts["-e"]=".etech.domain.net"
hosts["-k"]=".core.domain.net"
hosts["-m"]=".maint.domain.net"
hosts["-o"]=".ohgov.domain.net"

if [[ $1 == -h ]]
then
    usage
elif (( ${+hosts["$1"]} ))  # check if $1 is a key in hosts
then
    echo "Invalid option: $1"
    usage 1    # exit with status 1 to indicate error
fi

dirs=( $svn*$hosts["$1"]* ) # no need for ls here
for hostdir in $dirs
do
    host=$(echo $hostdir | grep -Eo "(\w|\.|-)*$")

    awk -v h=$host '
        /^Model/{m=$2}
        /^Model number/{m=$4}
        /^\*0/{m=$2}
        /^JUNOS Base OS boot/{v=$5}
        /^Junos:/{v="["$2"]"}
        /^BOOTLDR:/{v=$7} 
        /^JUNOS EX  Software Suite/{v=$5}
        /^ROM:/{v=$5}
        /^JUNOS Software Release/{v=$4}
        /^Chassis/{s=$2}
        /^Motherboard serial number/{s=$3}
        END {if(m!="number") {printf("%s %s %s %s\n",h,m,v,s)}}' \
      "$hostdir"/show.(version|chassis.hardware)        
done

或者,您可以对数组使用简洁的case

declare -A hosts # make associative array
hosts["-a"]=""
hosts["-b"]=".bb.domain.net"
hosts["-c"]=".cpe.domain.net"
hosts["-e"]=".etech.domain.net"
hosts["-k"]=".core.domain.net"
hosts["-m"]=".maint.domain.net"
hosts["-o"]=".ohgov.domain.net"
case $1 in
    -[abcekmno]) dirs=( $svn*${hosts["$1"]}* )
    ;;
    -h|help) usage
    ;;
    *) echo "Invalid option: $1"
       usage 1    # exit with status 1 to indicate error
    ;;
esac