从 iproute2 ss 输出中提取侦听 TCP 端口

从 iproute2 ss 输出中提取侦听 TCP 端口

我想找到进程(例如 apache2)正在侦听的端口,并仅将此(tcp)端口号打印到文件 file1.txt。

  • 这是我尝试过的命令:

    $ ss -atpln | grep 'apache2' | awk -F':' '{print $2}' > file1.txt
    
  • 这是我的输出(到 file1.txt):

    80     *
    

如何确保我的输出仅是端口号 (80),而不是“*”?


由 Ed Morton 编辑,添加 OP 中提供的重要信息一条评论:

请注意我的系统中的这个序列:

$ ss -atpln | grep apache2

输出是:

LISTEN 0 511 *:80 *:* users:(("apache2",pid=55338,fd=4),("apache2",pid=55337,fd=4),("apache2",pid=856,fd=4))

答案1

# ss -atpln | awk -F ':|[[:blank:]]+' '/apache2/ {print $5}'
443
443
443
80
80
80

它使用冒号或一个或多个“空白”字符(即空格或制表符)作为字段分隔符,这意味着我们要打印的字段(端口号)现在是字段 5。

grep如果您已经在使用,则无需使用awk- awk 完全能够在没有 grep 帮助的情况下进行模式匹配。

输出可能应该通过管道传输sort -u以仅打印唯一的端口号。

顺便说一句,如果您想知道为什么示例输出各有三行 443 和 80,在我的系统上,apache2 配置为在端口 80 和 443 上侦听三个不同的 IP 地址(针对三个不同的虚拟主机),而不仅仅是*:80*:443

答案2

我会使用perl并执行更明确的输入匹配来提取信息:

ss -Otpln |
  perl -slne '
    print $1 if m{
      ^ LISTEN \s+ # State
        \d+ \s+    # Recv-Q
        \d+ \s+    # Send-Q
        (?: 0\.0\.0\.0 | \[::\] | \*) : (\d+) \s+ # source address on INADDR_ANY
                                                  # or INADDR6_ANY only
        \S+ \s+    # dest address
        users: .* \(" \Q$name\E ",pid # match on process name
      }x && ! $already_seen{$1}++' -- -name=apache2

你的输出格式与我的不同(我得到的0.0.0.0是通配符IPv4地址,而[::]你得到的是IPv6地址*),这表明ss输出格式可能不是很稳定。ss您可以使用lsofwhich 具有用于批处理的模式,并且可以按进程名称进行匹配,而不是:

lsof -Fn -wnMPa -c apache2 -i tcp -s tcp:listen |
  sed -n 's/^n\*://p' |
  sort -nu

它还可以使其移植到非 Linux 系统。

相关内容