첫 번째 열에 함수를 적용하고 두 번째 열에 삽입

첫 번째 열에 함수를 적용하고 두 번째 열에 삽입

그래서 미친 듯이 찾아봤지만 아직 만족스러운 해결책을 찾지 못했습니다. 아래와 같이 출력이 있습니다.

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에서 실행하는 명령의 출력과 같이 줄의 일부에 공백이 포함되어 있으면 실패합니다.

귀하가 요청한 대로 다음은 2단계 방법입니다.

  1. 위와 같이 공백으로 구분된 필드와 줄바꿈으로 구분된 레코드를 사용하여 텍스트를 출력하는 대신 줄바꿈으로 구분된 필드와 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
  1. 개행으로 구분된 필드가 포함된 NUL 구분 레코드를 읽고, 입력을 읽을 때 각 필드의 최대 너비를 계산하고, 출력을 인쇄할 때 각 필드를 해당 너비로 출력하고 필드를 단일 OK로 재그룹화하는 awk 스크립트를 작성합니다.
$ 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

이를 위해서는 GNU awk와 같이 NUL로 구분된 입력을 읽을 수 있는 awk가 필요합니다. 경로 이름이나 다른 필드에는 개행 문자가 포함될 수 없다고 가정합니다.

위의 모든 작업을 하나의 awk 스크립트에서 실제로 수행하려면 외부 명령을 호출할 때마다 awk가 하위 쉘을 분리해야 하며 이는 속도가 느리고 올바르게 인용해야 함을 의미합니다(참조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

관련 정보