bashparsingpidwho

How can I get the PID column from the output of `who -u`?


Background

Calling who -Hu on my machine gives this result:

$ who -Hu
NAME     LINE         TIME             IDLE          PID COMMENT
rpi-first-boot-wizard tty7         1970-01-10 11:44 02:31        1204 (:0)
user-x   tty2         1970-01-07 20:16 00:10        2670
user-x   pts/0        4164607823021491175   .          2756 (192.168.203.57)

Problem

I am interested in the PID column for user-x. So what I want is 2670 and 2756.

What I tried

I looked through the man pages of who, but there are no options to get a specific column or to suppress certain columns.

I tried with who -u | grep user-x | tr -s ' ' | cut -d ' ' -f 5, but that only works for the row(s) that have the timestamp as a single number with no spaces. For some reason, some of the lines have a timestamp that includes spaces, so it's hard to parse.

What I want

It would be nice to have some simple bash command(s) that I could use to get the PIDs from the output. I'm just not sure exactly how to manipulate the strings correctly. I would rather not have to use a programming language to parse this output, but if I can't find out a nice way to do it with bash, then that's what I will have to end up doing.

Other info

In case this is an "XY problem," what I am really trying to do is kick a specific user out of my system, so I plan to pass these PIDs into kill, like who -u | grep user-x | tr -s ' ' | cut -d ' ' -f 5 | xargs kill. This worked like a charm until I started encountering sessions that use this wonky date format with the spaces. If there is another way to get the right PIDs that does not include using who, then that would also suffice.

Edit

Thanks to @jhnc's comment, I found that pkill -u user-x worked well and avoids this whole issue. Leaving the question as-is though, since @markp-fuso's answer actually does provide a solution to what was asked.


Solution

  • Assuming you want to capture the PIDs for some other reason besides issuing a kill (eg, appending to a log file) ...

    Using the following file to simulate OP's who -Hu call:

    $ cat who.out
    NAME     LINE         TIME             IDLE          PID COMMENT
    rpi-first-boot-wizard tty7         1970-01-10 11:44 02:31        1204 (:0)
    user-x   tty2         1970-01-07 20:16 00:10        2670
    user-x   pts/0        4164607823021491175   .          2756 (192.168.203.57)
    

    One approach using awk:

    cat who.out | awk -v user="user-x" '
    $1==user { gsub(/\([^)]+\)/,"")           # strip off the parenthesized string at end of line
               print $1, $NF                  # print 1st and last fields
             }
    '
    
    ########
    # or as a one-liner:
    
    cat who.out | awk -v user='user-x' '$1==user { gsub(/\([^)]+\)/,"") ; print $1, $NF}'
    

    These both generate:

    user-x 2670
    user-x 2756
    

    If you only need the PIDs in the output then change print $1, $NF to print $NF.

    In OP's case the call would look like:

    who -Hu | awk -v user='user-x' '$1==user { gsub(/\([^)]+\)/,"") ; print $1, $NF}'