我想找到进程(例如 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
您可以使用lsof
which 具有用于批处理的模式,并且可以按进程名称进行匹配,而不是:
lsof -Fn -wnMPa -c apache2 -i tcp -s tcp:listen |
sed -n 's/^n\*://p' |
sort -nu
它还可以使其移植到非 Linux 系统。