將功能應用於第一列並將其作為第二列插入
所以我一直在瘋狂尋找,但還是沒有找到滿意的解決方案。我有一些輸出,如下所示
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
也許是這樣的:
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)
,因此我將它放在一個變數中。
你說你不關心格式只要欄位是對齊的,只需選擇一個寬度足以滿足你的需要,然後:
$ 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-pass 方法 - 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 上執行的命令的輸出,這將失敗。
既然你問了,這裡有一個 2-pass 方法:
- 不是像上面那樣輸出使用空格分隔欄位和換行符分隔記錄的文本,而是生成使用換行符分隔欄位並使用 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