![将函数应用于第一列并将其插入为第二列](https://linux22.com/image/209994/%E5%B0%86%E5%87%BD%E6%95%B0%E5%BA%94%E7%94%A8%E4%BA%8E%E7%AC%AC%E4%B8%80%E5%88%97%E5%B9%B6%E5%B0%86%E5%85%B6%E6%8F%92%E5%85%A5%E4%B8%BA%E7%AC%AC%E4%BA%8C%E5%88%97.png)
所以我一直在疯狂的寻找,但仍然没有找到满意的解决方案。我有一些输出,如下所示
kdeconnec 1625 1000 11u IPv6 414426 0t0 UDP *:1716
vivaldi-b 1937 1000 263u IPv4 440390 0t0 UDP 224.0.0.251:5353
electron 9522 1000 23u IPv4 414465 0t0 TCP 192.168.0.17:58692->157.240.194.18:443 (ESTABLISHED)
flask 27084 1000 3u IPv4 109532 0t0 TCP 127.0.0.1:3000 (LISTEN)
firefox 27094 1000 99u IPv4 425877 0t0 TCP 192.168.0.17:34114->54.191.222.112:443 (ESTABLISHED)
python 36425 1000 3u IPv4 109532 0t0 TCP 127.0.0.1:3000 (LISTEN)
chromium 110937 1000 130u IPv4 439461 0t0 UDP 224.0.0.251:5353
我想exec_path_from_process_id
对每个值应用一个调用的函数第二列,并将其插入为第二柱子。结果如下。确切的格式(对齐)并不重要,只要对齐即可。
kdeconnec /usr/lib/kdeconnectd 1625 1000 11u IPv6 414426 0t0 UDP *:1716
vivaldi-b /opt/vivaldi/vivaldi-bin 1937 1000 263u IPv4 440390 0t0 UDP 224.0.0.251:5353
electron /usr/lib/electron/electron 9522 1000 23u IPv4 414465 0t0 TCP 192.168.0.17:58692->157.240.194.18:443 (ESTABLISHED)
flask /usr/bin/python3.10 27084 1000 3u IPv4 109532 0t0 TCP 127.0.0.1:3000 (LISTEN)
firefox /usr/lib/firefox/firefox 27094 1000 99u IPv4 425877 0t0 TCP 192.168.0.17:34114->54.191.222.112:443 (ESTABLISHED)
python /usr/bin/python3.10 36425 1000 3u IPv4 109532 0t0 TCP 127.0.0.1:3000 (LISTEN)
chromium /usr/lib/chromium/chromium 110937 1000 130u IPv4 439461 0t0 UDP 224.0.0.251:5353
kioslave5 /usr/lib/kf5/kioslave5 133514 1000 6u IPv4 499063 0t0 TCP 192.168.0.17:54238->84.208.4.225:443 (ESTABLISHED)
我当前的代码一团糟,但至少我让它工作了。唯一的限制是它必须在 bash 3.2+ 上运行
listeners=$(
lsof -Pnl +M -i |
awk -F" " '!_[$1]++' |
tail -n +2
)
function exec_path_from_process_id () {
local pid="${1}"
path=$(readlink -f /proc/"$pid"/exe)
if [ -z "${path}" ]; then
path=$(awk '{print $(NF)}' <<< $(ls -alF /proc/"$pid"/exe))
fi
echo ${path:-null}
}
pids=($(awk '{ print $2 }' <<< "$listeners"))
IFS=$'\n' read -rd '' -a listeners_array <<< "$listeners"
IFS=$'\n' read -rd '' -a paths <<< $(for i in "${pids[@]}"; do exec_path_from_process_id "$i"; done)
for i in "${!pids[@]}"; do
row="${listeners_array[i]}"
row=$(awk -v r="${paths[i]}" '{ print $1 " " r " " $2 " " $3 " " $4 " " $5 " " $6 " " $7 " " $8 " " $9 " " $10}' <<< $row)
printf '%s\n' "${row[@]}"
done | column -t
答案1
也许是这样的:
lsof -Pnl +M -i | awk '
# Use: NR > 1 to skip header
NR > 1 && !x[$1]++ {
# realpath -m
# (no path components need exist or be a directory)
cmd = "realpath -m /proc/"$2"/exe"
cmd | getline path
close(cmd)
# We can edit field $2 and print $0
$2 = path" "$2
print $0
}' | column -t
该行cmd | getline path
执行命令cmd
并将输出读取到变量中path
。除非有人这样做,否则该命令不会关闭close(expression)
,因此我将其放在变量中。
答案2
您说过只要字段对齐即可,您不关心格式,只需选择一个足以满足您需要的宽度,然后:
$ while read -r a pid b; do
printf "%-12s%-10s%10s %s\n" "$a" "<$(wc -c <<<"$pid")>" "$pid" "$b"
done < <(lsof -Pnl +M -i)
kdeconnec <5> 1625 1000 11u IPv6 414426 0t0 UDP *:1716
vivaldi-b <5> 1937 1000 263u IPv4 440390 0t0 UDP 224.0.0.251:5353
electron <5> 9522 1000 23u IPv4 414465 0t0 TCP 192.168.0.17:58692->157.240.194.18:443 (ESTABLISHED)
flask <6> 27084 1000 3u IPv4 109532 0t0 TCP 127.0.0.1:3000 (LISTEN)
firefox <6> 27094 1000 99u IPv4 425877 0t0 TCP 192.168.0.17:34114->54.191.222.112:443 (ESTABLISHED)
python <6> 36425 1000 3u IPv4 109532 0t0 TCP 127.0.0.1:3000 (LISTEN)
chromium <7> 110937 1000 130u IPv4 439461 0t0 UDP 224.0.0.251:5353
上面假设您的第一列不包含任何空格。
显然,只需更改<$(wc -c <<<"$pid")>
为您需要运行的实际命令,并且第一个%-10s
更改为该命令可以输出的任何最大宽度字符串。如果您确实觉得该宽度没有可以使用的最大值,请告诉我们,然后将采用 2 遍方法 - 1 生成输出,然后 2 格式化输出。如果您对column -t
使用格式感到满意,那么它会是(替换file
为<(lsof -Pnl +M -i)
显然我实际上没有可用的):
$ while read -r a pid b; do
printf "%s %s %s %s\n" "$a" "<$(wc -c <<<"$pid")>" "$pid" "$b"
done < file | column -t
kdeconnec <5> 1625 1000 11u IPv6 414426 0t0 UDP *:1716
vivaldi-b <5> 1937 1000 263u IPv4 440390 0t0 UDP 224.0.0.251:5353
electron <5> 9522 1000 23u IPv4 414465 0t0 TCP 192.168.0.17:58692->157.240.194.18:443 (ESTABLISHED)
flask <6> 27084 1000 3u IPv4 109532 0t0 TCP 127.0.0.1:3000 (LISTEN)
firefox <6> 27094 1000 99u IPv4 425877 0t0 TCP 192.168.0.17:34114->54.191.222.112:443 (ESTABLISHED)
python <6> 36425 1000 3u IPv4 109532 0t0 TCP 127.0.0.1:3000 (LISTEN)
chromium <7> 110937 1000 130u IPv4 439461 0t0 UDP 224.0.0.251:5353
但如果行的任何部分包含空格,例如您在 pid 上运行的命令的输出,则会失败。
既然你问了,这里有一个两遍的方法:
- 不要像上面那样输出具有空格分隔字段和换行符分隔记录的文本,而是生成使用换行符分隔字段和 NUL 分隔记录的输出:
while read -r a pid b; do printf "%s\n%s\n%s\n%s\0" "$a" "<$(wc -c <<<"$pid")>" "$pid" "$b"; done < file
- 编写一个 awk 脚本,读取包含换行符分隔字段的 NUL 分隔记录,在读取输入时计算每个字段的最大宽度,并在打印输出时以该宽度输出每个字段,将字段重新组合成单行:
$ while read -r a pid b; do printf "%s\n%s\n%s\n%s\0" "$a" "<$(wc -c <<<"$pid")>" "$pid" "$b"; done < file |
awk -v RS='\0' -F'\n' '
{ recs[NR]=$0; for (i=1; i<=NF; i++) wids[i]=(length($i)>wids[i] ? length($i) : wids[i]) }
END { for (n=1; n<=NR; n++) { $0=recs[n]; for (i=1;i<=NF;i++) printf "%-*s%s", wids[i], $i, (i<NF ? OFS : ORS) } }
'
kdeconnec <5> 1625 1000 11u IPv6 414426 0t0 UDP *:1716
vivaldi-b <5> 1937 1000 263u IPv4 440390 0t0 UDP 224.0.0.251:5353
electron <5> 9522 1000 23u IPv4 414465 0t0 TCP 192.168.0.17:58692->157.240.194.18:443 (ESTABLISHED)
flask <6> 27084 1000 3u IPv4 109532 0t0 TCP 127.0.0.1:3000 (LISTEN)
firefox <6> 27094 1000 99u IPv4 425877 0t0 TCP 192.168.0.17:34114->54.191.222.112:443 (ESTABLISHED)
python <6> 36425 1000 3u IPv4 109532 0t0 TCP 127.0.0.1:3000 (LISTEN)
chromium <7> 110937 1000 130u IPv4 439461 0t0 UDP 224.0.0.251:5353
这需要一个可以读取 NUL 分隔输入的 awk,例如 GNU awk。它假定您的路径名或其他字段都不能包含换行符。
如果您真的想在一个 awk 脚本中完成上述所有操作,这意味着每次调用外部命令时 awk 都必须分离出一个子 shell,这会很慢,并且您必须确保正确引用(看http://awk.freeshell.org/AllAboutGetline)但是在这里,假设您不关心在输入字段中保留空格,但路径中的非换行符空格就可以了:
$ awk '
{
recs[NR] = $0
for (i=1; i<=NF; i++) {
lgth = length($i)
wids[i] = ( lgth > wids[i] ? lgth : wids[i] )
}
cmd = "wc -c <<<\047" $2 "\047"
paths[NR] = ( (cmd | getline line) > 0 ? line : "N/A" )
close(cmd)
lgth = length(paths[NR])
pathWid = ( lgth > pathWid ? lgth : pathWid )
}
END {
for (n=1; n<=NR; n++) {
$0 = recs[n]
for (i=1; i<=NF; i++) {
if ( i == 2 ) {
printf "%-*s%s", pathWid, paths[n], OFS
}
printf "%-*s%s", wids[i], $i, (i<NF ? OFS : ORS)
}
}
}
' < file
kdeconnec 5 1625 1000 11u IPv6 414426 0t0 UDP *:1716
vivaldi-b 5 1937 1000 263u IPv4 440390 0t0 UDP 224.0.0.251:5353
electron 5 9522 1000 23u IPv4 414465 0t0 TCP 192.168.0.17:58692->157.240.194.18:443 (ESTABLISHED)
flask 6 27084 1000 3u IPv4 109532 0t0 TCP 127.0.0.1:3000 (LISTEN)
firefox 6 27094 1000 99u IPv4 425877 0t0 TCP 192.168.0.17:34114->54.191.222.112:443 (ESTABLISHED)
python 6 36425 1000 3u IPv4 109532 0t0 TCP 127.0.0.1:3000 (LISTEN)
chromium 7 110937 1000 130u IPv4 439461 0t0 UDP 224.0.0.251:5353