我正在尝试使用 awk 和 ss 的输出来打印第四列。有时它会起作用,但有时它会错误地合并或拆分列。我尝试了几种不同的 FS 选项,这里是两个或多个空格,因为字段标题包含一个空格。
这给了我第五列和一个空白标题:
$ ss -tn
State Recv-Q Send-Q Local Address:Port Peer Address:Port
ESTAB 0 36 172.31.19.34:22 172.115.128.85:64478
ESTAB 0 0 [::ffff:172.31.19.34]:80 [::ffff:172.115.128.85]:65446
$ ss -tn | awk -F '[[:space:]][[:space:]]+' '{print $4}'
172.115.128.86:64478
[::ffff:172.115.128.86]:65446
这里相同的命令给了我第四列,这就是我想要的。
$ ss -tn
State Recv-Q Send-Q Local Address:Port Peer Address:Port
ESTAB 0 36 172.31.19.34:22 172.115.128.85:64478
$ ss -tn | awk -F '[[:space:]][[:space:]]+' '{print $4}'
Local Address:Port
172.31.19.34:22
我知道cut
可能更容易,但我正在使用,awk
因为我想做进一步的处理。
添加细节:我不确定为什么 ss 显示此 IPv6 样式地址。这是从我的笔记本电脑到 apache 服务器的连接,但我的笔记本电脑没有 IPv6 地址。
答案1
作为穆鲁暗示在一个评论,awk
可能会持续工作。可以变化的是 的输出中的间距ss
。
结果ss -nt
1输出了七列,标题分别是:State
, Recv-Q
, Send-Q
, Local Address
, Port
, Peer Address
, Port
。第四列和第五列之间用冒号 ( :
) 分隔;第六和第七也是同样的情况。所有其他内容均由空格字符分隔。
所有列都在需要对齐的地方填充了空格。第四个和第六个填充在其左侧,所有其他填充在右侧。
可能会发生进一步的填充:
如果 的输出
ss -nt
定向到终端:如果其行的最小长度(计算为每个字段的最长内容加上最小间距(六个字符)之和)小于终端的宽度,则每行通过均匀填充扩展到终端的宽度所有带有空格的列;
否则,线会被打断,并且字段会跨线对齐(如上填充,直到终端的宽度)。
如果 的输出
ss -nt
不定向到终端(例如,它通过管道传输或重定向到常规文件),则行的实际长度定义为 80 的最小倍数,该倍数高于上面定义的最小长度。所有列均均匀地填充空格,以达到总行长度,即 80、160、240、...字符2。
因此,不能保证两列将被两个或多个空格分隔,从而使得该序列对于分割来说不可靠。
尽管如此,您仍然可以以相当安全的方式处理 的输出ss -tn
,注意列标题是已知且固定的,并且除了标题之外,其任何列都不应包含空格3:
ss -nt | sed '
1 s/[ ]Address:/_Address|/g # Remove the known spaces from column
# headers; also, change ":" into "|"
s/:\([^:|]*[ ]\)/|\1/g # Change the colons used as separators
# into vertical bars "|", to avoid
s/:\([^:|]*\)$/|\1/g # confusion with those in IPv6s
' | awk -v FS='\\||[ ]+' -v OFS=":" ' # Split on sequences of one or more
{ print $4,$5 } # spaces OR on any vertical bar
'
这将仅打印第四和第五列(本地地址和端口),以冒号分隔。请注意,使用不是默认的单个空格的字段分隔符awk
将识别八列而不是七列,并且如果您执行 a { $1=$1; print; }
,它将OFS
在最后一列右侧填充有 at 的任何行的末尾打印一个至少有一个空格。
1其他选项(例如-i
, -e
, -m
)会极大地改变 的输出ss
。为了简洁和清楚起见,我们将只关注这个确切的命令。
2近似且可能不精确。但这与这个问题/答案的要点无关。
3显然这并不能得到保证,我们故意不尝试涵盖所有不常见的情况。
答案2
为什么 awk 字段分隔符不能一致工作?
是的,不可靠的是 的输出中的空格数量ss
。
第四栏,这就是我想要的。
然后只需删除标题(-H
)并选择第四列:
$ ss -taH | awk '{print $4}'
172.31.19.34:22
[::ffff:172.31.19.34]:80
由于标头是固定的,只需将其添加回来(如果需要):
$ echo "Local Address:Port"
Local Address:Port
完整命令:
$ echo "Local Address:Port"; ss -tnH | awk '{print $4}'
Local Address:Port
172.31.19.34:22
[::ffff:172.31.19.34]:80
是的,您的计算机始终具有 IPv6(一个或多个)地址。如果您不需要它们,只需询问 IPv4 地址:
$ ss -tnH4 | awk '{print $4}'
172.31.19.34:22