[shell] awk 获取指定IP对应的网口

引子

项目中需要根据 Linux主机 IP 地址获取其对应网口名称(如 IP地址为192.168.130.12,其对应的网口为 ens33)。然后在该网口利用 tcpdump 执行抓包命令:

IP_ADDRESS=192.168.130.12
INTERFACE_NAME=`ifconfig | awk -F ":" '/'$IP_ADDRESS'/{print a}{a=$1}'`
tcpdump -i $INTERFACE_NAME-s0 -w fileName.panpng

典型的 ifconfig 配置如下(为了后续描述方便,这里添加上了行号):

[lm@localhost ~]$ ifconfig 
  1 br0: flags=4163<UP,BROADCAST,RUNNING,MULTICAST>  mtu 1500
  2         inet6 fe80::20c:29ff:fe7a:d306  prefixlen 64  scopeid 0x20<link>
  3         ether 00:0c:29:7a:d3:06  txqueuelen 1000  (Ethernet)
  4         RX packets 0  bytes 0 (0.0 B)
  5         RX errors 0  dropped 0  overruns 0  frame 0
  6         TX packets 16  bytes 2292 (2.2 KiB)
  7         TX errors 0  dropped 0 overruns 0  carrier 0  collisions 0
  8 
  9 ens33: flags=4163<UP,BROADCAST,RUNNING,MULTICAST>  mtu 1500
 10         inet 192.168.130.12  netmask 255.255.255.0  broadcast 192.168.130.255
 11         inet6 fe80::20c:29ff:fe7a:d310  prefixlen 64  scopeid 0x20<link>
 12         ether 00:0c:29:7a:d3:10  txqueuelen 1000  (Ethernet)
 13         RX packets 3051  bytes 662216 (646.6 KiB) 
 14         RX errors 0  dropped 0  overruns 0  frame 0
 15         TX packets 385  bytes 54431 (53.1 KiB)
 16         TX errors 0  dropped 0 overruns 0  carrier 0  collisions 0

最初想到的是先定向到一个文件,然后 grep 搜索IP地址,知道行数后,上面的一行就是其所对应网口行,最后awk提取出第一列就可以。俗话说,“高手在民间”,查到网友有分享更为简单的一行命令用法:

[lm@localhost ~]# ifconfig | awk '/192.168.130.12/{print a}{a=$1}'
ens33:

看起来的确是,简单,精炼。可惜没太看懂,就查询了一下具体实现。

awk简介

awk 是数据处理工具,相比较于 grep、sed 常常是针对一个整行的处理,awk 更多是将一行分成数个“字段”来处理。因此,awk 非常适合在文件或字符串中基于指定规则浏览和抽取信息。

语法规则

awk 通常运作模式是这样的:

awk '条件类型1 {动作 1} 条件类型2 {动作 2} ...' fileNames

或者

awk 'pattern {action}' fileNames

其中:pattern 表示需要匹配的特定模式。action 表述对数据的处理动作。

实例解析

还是通过命令来先了解下运行原理。如:打印出网口的各个IP地址。

[lm@localhost ~]$ ifconfig | grep "inet " | awk '{print $1 "\t" $2}'
inet	172.16.64.238
inet	192.168.130.12
inet	127.0.0.1
inet	192.168.122.1

每一行的每个字段都是有变量名称的,那就是 $1, $2… 等变量名
称。以上面的例子来说, inet是 $1 ,因为它位于第一列,而 192.168.130.12 是第二列, 所以他就是 $2 啦!后面以此类推。
此外,还有个变量!那就是 $0 ;$0 代表【一整行内容】的意思。以上面的例子来说,第一行的 $0 代表的就是【inet … 】那一行。示例中最后的 IP 地址对应的是 $2 的内容。

[lm@localhost ~]$ ifconfig | grep "inet " | awk '{print $0 "\t" $2}'
        inet 172.16.64.238  netmask 255.255.255.0  broadcast 172.16.64.255	172.16.64.238
        inet 192.168.130.12  netmask 255.255.255.0  broadcast 192.168.130.255	192.168.130.12
        inet 127.0.0.1  netmask 255.0.0.0	127.0.0.1
        inet 192.168.122.1  netmask 255.255.255.0  broadcast 192.168.122.255	192.168.122.1

awk 处理流程

根据 awk 语法规则,其具体处理流程如下:

awk 'pattern {action}' fileNames
  1. 读入第一行,将第一行的内容填入 $0, $1, $2… 等变量当中;
  2. 依据 pattern(条件类型)的模式或者规则,判断是否需要进行后面的"动作";
  3. 完成所有动作与pattern(条件类型);
  4. 若还有后续【行】的数据,则重复上面 1~3 的步骤,直到所有数据都读完。

命令解析

回到我们最初提出的问题,如果理解开头提到的获取指定 IP 地址所对应的网口呢?

[lm@localhost ~]# ifconfig | awk '/192.168.130.12/{print a}{a=$1}'
ens33:

首先网上高手给出的解决方案满足的是 awk 【规则表达式]

awk '/REG/{action} ' fileNames

其中,/REG/为正则表达式,可以将 $0 中,满足条件的记录送入到:action 进行处理。下面具体分析一下处理过程。

  1. 处理第一行的时候,是IP地址 为 192.168.130.12 那一行么吗?明显不是,此时处理的第一行(填入$0中)为 “br0: flags=4099<UP,BROADCAST,MULTICAST> mtu 1500”。 这一行里面是没有 192.168.130.12 的,因此那个 pattern 不匹配,第一个 {action} 不执行(即不执行 print a)。但执行了后面的a=$1,即 a 的内容为 "br0: "(默认按照空格分割)。

执行第一行后,此时 $0 内容为:

br0: flags=4099<UP,BROADCAST,MULTICAST> mtu 1500"

$1内容为:

br0:

  1. 根据 【awk 处理流程】,接着重复处理第二行,与第一行处理类似,还是第一个 {action} 不执行(即不执行 print a)。而是执行了后面的a=$1,即 a 的内容此时为 “ether”(默认按照空格分割)。

执行第二行后,此时 $0 内容为:

ether e2:c3:bc:d9:94:d7 txqueuelen 1000 (Ethernet)

$1内容为:

ether

  1. 接着重复处理第三行、第四行、… 、第九行。与前面类似,执行完毕第九行后。
    $0 内容为:

ens33: flags=4163<UP,BROADCAST,RUNNING,MULTICAST> mtu 1500

$1内容为(此时后面有个 “:” 号的):

ens33:

  1. 当执行到第十行的时候,该行中包含有 192.168.130.12,此时 pattern 匹配生效,第一个 {action} 执行(即 print a)。由于 a 的内容为 “ens33:”,所以输出(距离我们期望的目标已经非常接近了,最后的 “:” 号的,可以通过 awk 的 -F 选项来切分):
 ens33:
  1. 后续的处理,与前面执行第一行、第二行、… 类似,这里不在赘述。

还没结束

我们在编写 shell 脚本的时候,针对 IP 地址,更多的情况是使用变量,或者作为参数从外面传递进去,而不是直接将 IP 地址 hardcode 进去。应该说实际的 code 应该是下面这个样子:

IP_ADDRESS=192.168.130.12
INTERFACE_NAME=`ifconfig | awk -F ":" '/$IP_ADDRESS/{print a}{a=$1}'`

然而非常遗憾的是,貌似输出的结果跟我们上面测试的并不一样。这里输出为空。Why? 哪里出问题了?

建议先阅读shell十三问之4:""(双引号)与’’(单引号)差在哪?

从""(双引号)与’’(单引号) 差别?我们了解到,变量 $IP_ADDRESS 在 hard quote 中被关闭了。因此,正确的形式应该是下面的样子:

IP_ADDRESS=192.168.130.12
INTERFACE_NAME=`ifconfig | awk -F ":" '/'$IP_ADDRESS'/{print a}{a=$1}'`

#It can also be like this.
INTERFACE_NAME=`ifconfig | awk -F ":" '/'"$IP_ADDRESS"'/{print a}{a=$1}{print a}'`

思考

假如我想知道每次执行过程中 a 变量具体内容是什么,并且打印出 a 的内容,那么可以使用了下面的命令执行么?此时的 $INTERFACE_NAME 变量还是我们期望的 ens33 么?如果不能,Why?

IP_ADDRESS=192.168.130.12
INTERFACE_NAME=`ifconfig | awk -F ":" '/'$IP_ADDRESS'/{print a}{a=$1}{print a}'`

参考

shell 用ip获取网络接口
Linux三剑客之awk命令
shell脚本,awk如何处理文件中上下关联的两行
shell十三问之4:""(双引号)与’’(单引号)差在哪?

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值