Is there a linux command to determine the window IDs associated with a given process ID?

前端 未结 6 2001
借酒劲吻你
借酒劲吻你 2020-12-22 23:41

Given a process iD of XX, I\'d like to have a list of any window id\'s where _NET_WM_PID = XX. Even better would be the oldest still active window id if possible.

I

6条回答
  •  余生分开走
    2020-12-23 00:20

    xterm $WINDOWID feature

    Under xterm environment as some other implementation, you could find this variable:

    echo $WINDOWID
    58720292
    

    So for any other pid:

    Shortly by using sed:

    targetpid=12345
    sed -zne 's/WINDOWID=//p' /proc/$targetpid/environ
    

    ...

    xdotool windowactivate $(sed -zne 's/WINDOWID=//p' /proc/$targetpid/environ)
    

    Or in a pure bash function:

    getWinFromPid () { 
        local pid=$1 array line
        [ -z "$pid" ] || [ ! -d /proc/$pid ] && return -1
        local -n result=${2:-winIDfromPid[$pid]}
        mapfile -d $'\0' -t array 

    Then

    getWinFromPid 123456 myWinId
    xdotool windowactivate $myWinId
    

    For other term, like gnome-terminal:

    This is strong because we don't want pid of terminal process, but pid of shell using terminal. For sample:

    wmctrl -lp
    

    don't show wanted pids!

    So we have to navigate in hierarchy of process

    1. Get Window ID from process ID

    1a. Current active terminal window

    From active session himself:

    SHWINID=$(xprop  -root | sed -ne 's/^_NET_ACTIVE_WINDOW.*[)].*window id # //p')
    

    This work as you type this in any active terminal console.

    Then now, with xdotool:

    sleep 12; xdotool windowactivate $SHWINID
    

    You can now switch to another window, will be back in 12 seconds.

    1b. Window ID from any shell or subprocess ID

    I wrote this little function:

    getWinFromPid () { 
        local pid=$1 ttypid crtpid wid xprop ttycheck
        [ -z "$pid" ] || [ ! -d /proc/$pid ] && return -1
        local -n result=${2:-winIDfromPid[$pid]}
        read ttycheck < <(ps ho tty $pid)
        ttypid=$ttycheck
        while [ "$ttypid" = "$ttycheck" ]; do
            crtpid=$pid
            read pid ttypid < <(ps ho ppid,tty $pid)
        done
        result=
        while [ -z "$result" ] && read wid; do
            xprop=$(xprop -id $wid)
            [ "$xprop" ] && [ -z "${xprop//*_NET_WM_DESKTOP*}" ] &&
                [ -z "${xprop//*_NET_WM_PID(CARDINAL) = $crtpid*}" ] && result=$wid
        done < <(xwininfo -root -children -all |
           sed -e '1,/children:$/d;s/^ *\(0x[0-9a-fA-F]\+\) .*/\1/p;d')
    }
    

    Then

    getWinFromPid  []
    

    If no variable name submited, this will populate global array $winIDfromPid with pid id as index number:

    getWinFromPid 1234 winId
    echo $winId
    0x0100012345
    
    getWinFromPid 1234
    echo ${winIDfromPid[1234]}
    0x0100012345
    
    declare -p winIDfromPid 
    declare -a winIDfromPid=([1234]="0x0100012345")
    

    Nota: this was tested with xterm, mate-terminal, konsole and gnome-terminal.

    Nota2: If you already have wmctrl installed, you could replace two last lines of function:

        done < <(xwininfo -root -children -all |
           sed -e '1,/children:$/d;s/^ *\(0x[0-9a-fA-F]\+\) .*/\1/p;d')
    

    by:

        done < <(wmctrl -l|sed -ne 's/^ *\(0x[0-9a-fA-F]\+\) .*/\1/p');}
    

    function will become approx 2time faster.

    2. Get process running PID from a window ID

    winID=0x123456
    ps --ppid $(xprop -id $winID _NET_WM_PID|sed s/.*=//) ho sid |
        xargs -I{} -n1 ps --sid {} fw
    

    or without ID, you will have to click with mouse:

    ps --ppid $(xprop _NET_WM_PID|sed s/.*=//) ho sid|xargs -I{} -n1 ps --sid {} fw
    

    Into a function

    psWin() {
        ps --ppid $(xprop ${1+-id} $1 _NET_WM_PID|sed s/.*=//) ho sid |
            xargs -I{} -n1 ps --sid {} fw
    }
    

    Then:

    psWin $SHWINID
      PID TTY      STAT   TIME COMMAND
    30529 pts/2   Ss     0:00 bash
    19979 pts/2   S+     0:00  \_ bash
    19982 pts/2   S+     0:00      \_ xargs -I{} -n1 ps --sid {} fw
    19986 pts/2   R+     0:00          \_ ps --sid 30529 fw
    

    3. List of shell windows, with process

    Finally, there is a little function for showing a list of window with process.

    shWinList () {
        local pids=() wids=() wtitl=() ttys=() pid ttypid wpid crtpid line title desk ttycheck
        for pid in $(ps axho pid,tty| sed -ne 's/ pts.*//p') ;do     # list pid / tty
            wpid=$pid ttypid=
            read ttycheck < <(ps ho tty $pid)
            ttypid=$ttycheck
            while [ "$ttypid" = "$ttycheck" ]; do
                crtpid=$wpid
                read wpid ttypid < <(ps ho ppid,tty $wpid)
            done
            [ -e /proc/$pid ] && pids[crtpid]+=$pid\  ttys[crtpid]=$ttycheck
        done
        while read wid; do   title= pid= desk=                       # list wid / tty
            while read line; do
                [ "$line" ] && { 
                    [ -z "${line%%_NET_WM_PID*}" ] && pid=${line##*= }
                    [ -z "${line%%WM_NAME*}" ] &&
                        title=${line#*\"} title=${title%\"*}
                    [ -z "${line%%_NET_WM_DESKTOP(*}" ] && desk=${line##*= } ;}
            done < <(xprop -id $wid)
            [ "${pids[pid]}" ] && [ "$title" ] && [ "$desk" ] &&
                wtitl[16#${wid#0x}]=${title} wids[16#${wid#0x}]=${pids[pid]} \
                     ttys[16#${wid#0x}]=${ttys[pid]}
        done < <(xwininfo -root -children -all |
                     sed -ne 's/^ *\(0x[0-9a-fA-F]\+\) .*/\1/p')
        for xwin in ${!wids[@]} ;do  out=                            # merge & print
            printf "  0x%x %-9s %-40s " $xwin "${ttys[$xwin]}" "${wtitl[$xwin]}"
            for pid in ${wids[$xwin]} ;do
                mapfile -d '' cmdl < /proc/$pid/cmdline
                echo -n " $pid[${cmdl[*]}]"
            done ; echo
        done
    }
    

    Then

    shWinList
      0xa600024 pts/42    user@hostloc: /tmp            14817[bash]
      0x1c00024 pts/3     user@hostloc: ~               29349[watch ps --tty pts/3 fw] 31989[bash]
      0x4600024 pts/16    user@remote: ~                14441[ssh user@remote]
      0x6000024 pts/43    user@hostloc: ~               5728[bash]
    

提交回复
热议问题