55

How can I ask ps to display only user processes and not kernel threads?

See this question to see what I mean...

Totor
  • 20,040

10 Answers10

58

This should do (under Linux):

ps --ppid 2 -p 2 --deselect

kthreadd (PID 2) has PPID 0 (on Linux 2.6+) but ps does not allow to filter for PPID 0; thus this work-around.

See also this equivalent answer.

Totor
  • 20,040
Hauke Laging
  • 90,279
  • 1
    Nice, but how guaranteed is it that kthreadd is always PID 2? – l0b0 Jun 07 '13 at 15:21
  • @l0b0 I have no idea :-) You could do this in two steps: Determine the PID of kthreadd, then build the according ps call. How guaranteed is it that this thing will "always" be called "kthreadd"? A safe solution would be more complicated, run ps normally and parse the output, do some tests maybe. – Hauke Laging Jun 07 '13 at 15:38
  • Others have taught me it's a bad idea to look for the PID by looking for process names in ps output. There could easily be any number of processes with the same name. – l0b0 Jun 07 '13 at 19:51
  • 2
    In Linux 2.4 on x86 arch at least, those processes had ppid 1 so couldn't be distinguished that way. – Stéphane Chazelas Jun 07 '13 at 20:29
  • Sorry for being a "ps noob", but how would I get an output similar to ps aux with that command? – Totor Nov 22 '13 at 00:22
  • 3
    to be like "ps -ef" do "ps --ppid 2 -p 2 --deselect -f" and to do it like "ps aux" do "ps --ppid 2 -p 2 --deselect u" – Peter Aug 08 '14 at 11:22
  • 1
    @Totor I checked and looks like it's the x flag that doesn't work with this. ps au --ppid 2 -p 2 --deselect works OK. – Sankalp Jul 25 '18 at 08:54
  • @Sankalp The --deselect option (can be shortened as -N) negates the specified conditions. ps ax shows the processes owned by anyone, with or without a tty (basicly all proceses), so ps ax --deselect shows none. If you look carefully, ps a --deselect won't show any process with a tty. – Rémi Svahn Mar 31 '22 at 08:47
16

In practice I found the following idiom enough:

ps auxf | grep -v ]$

It filters lines ending with brackets, which might result omitting unwanted entries but it's very unlikely. In exchange it's quite easy to remember and relatively quick to type.

Some processes like avahi-daemon add to their process name information in brackets (the hostname in the case of avahi-daemon) and will be filtered out by this command.

countermode
  • 7,533
  • 5
  • 31
  • 58
onetom
  • 161
12

One way to recognize kernel processes is that they don't use any user memory, so the vsz field is 0. This also catches zombies (thanks to Stephane Chazelas for this observation), which can be eliminated based on their status.

ps axl | awk '$7 != 0 && $10 !~ "Z"'

To list just the PIDs:

ps -e -o pid= -o state= -o vsize= | awk '$2 != "Z" && $3 != 0 {print $1}'
8

One of the particularity of those processes is that they are not backed by an executable file, so you could do (in zsh):

ps /proc/[0-9]*/exe(^-@:h:t)

Or with any POSIX shell:

ps -p "$(find -L /proc/[0-9]*/exe ! -type l | cut -d / -f3 | paste -sd , -)"

That is check for processes whose /proc/<pid>/exe is a link to a file.

But that means you need to be superuser to be able to check the state of the /proc/<pid>/exe symlink.

Edit: As it happens the zombie processes (at least) satisfy the same condition, so if you don't want them excluded, you'd have to add them back. Like:

ps -p "$(
  { find -L /proc/[0-9]*/exe ! -type l | cut -d / -f3
    ps -Ao pid=,state= | sed -n 's/ Z//p'
  } | paste -sd , -)"

Note that ps -f shows those process names in square brackets not because they're kernel processes, but because they have an empty argv[] (so ps shows the process name instead of argv[0] there). You can have a user space process with an empty argv[] as well and you can have a process name with an argv[0] that's of the form [some-string] so filtering the ps output based on those square brackets is not a foolproof option.

  • This is non standard shell syntax, I reckon. – Totor Jun 07 '13 at 14:28
  • 1
    @Totor, as I said, the first one is zsh syntax. The second is standard POSIX sh (and ps and find and cut and paste) syntax. Of course /proc is not specified by POSIX. – Stéphane Chazelas Jun 07 '13 at 14:42
  • Accepting this answer because it's universal (thanks for the edit). However, Hauke Laging's answer is also pretty nice and straightforward as long as you don't deal with a 2.4 kernel. – Totor Jun 08 '13 at 19:12
  • @Totor, Hauke's answer also has the advantage of not requiring superuser priviledge. My answer works with 2.4 and 2.6/3 kernels, but I suppose there's not guarantee it will work in 4.x anyway. – Stéphane Chazelas Jun 08 '13 at 20:01
  • Hmm, you're right, I didn't think about root privileges. It can lead to mistakes since you still get an answer when you're not root, but it's different (so you must be cautious when counting them with, say wc -l). Well, I will accept Hauke Laging's answer then, and give you an upvote. ;) – Totor Jun 09 '13 at 22:41
  • Stephane, can you edit your answer to specify that it works "as expected" (displays all user processes) only if you're root, please? – Totor Jun 10 '13 at 15:12
  • @Totor, I did from the start. root is the usual username with superuser priviledge (uid 0) – Stéphane Chazelas Jun 10 '13 at 16:51
  • Mea culpa, I didn't read carefully enough. Thank you Stephane. – Totor Jun 10 '13 at 21:15
3

Although the question has aged a bit, there is an interesting new approach: Since version 4 of the procps package, you can set the environment variable LIBPROC_HIDE_KERNEL. If set, ps(1) and top(1) will display user space processes, only.

Extract from the manual:

LIBPROC_HIDE_KERNEL

Set this to any value to hide kernel threads normally displayed with the -e option. This is equivalent to selecting --ppid 2 -p 2 --deselect instead. Also works in BSD mode.

Totor
  • 20,040
1

For anyone trying this in busybox where ps is heavily simplified and the output is different, this variant of Gilles' great answer works well:

ps -o pid,user,comm,vsz,stat | awk '$4 != 0 && $5 !~ "Z"'

As per Gilles' answer, the methodology here is to find processes that don't use any user memory (`vsz col == 0), and filter out zombie processes (status col is not 'Z').

Output columns can be adjusted easily, as long as the 1-based awk field numbers are adjusted accordingly. See the options your ps has available by putting in a bogus value and it will tell you. For example:

$ ps -o foo
ps: bad -o argument 'foo', supported arguments: user,group,comm,args,pid,ppid,pgid,tty,vsz,stat,rss
Russ
  • 903
1

You could also just parse the ps output and look for process names that are not in brackets:

ps aux | awk '$NF!~/^\[.+\]$/'
terdon
  • 242,166
  • A slightly less unreliable way to get the list of users you're interested in: awk -F: '$7 ~ home { print $1 }' /etc/passwd -- but you'll still get processes that mention any such user name, and you'll leave the temp file lying around. I'll withdraw my downvote, but only because your third solution is reasonable. – Keith Thompson Jun 07 '13 at 20:31
  • Bah, you're right all the way, @KeithThompson, removed the others, they're not worth it. Could you help me clean up the (now) obsolete comments? – terdon Jun 07 '13 at 20:38
  • 3
    Note that $NF is the last word of the command line in ps aux output. Non-kernel processes can have [...] there. As I said in my answer the [xxx] notation is not because they are kernel processes, but because they have no command line (no argument) which is also allowed of non-kernel processes. – Stéphane Chazelas Jun 07 '13 at 22:44
0

If you only need the counts ... I had a similar need to filter kernel vs. user processes, but I only needed the respective counts of each. This was my solution:

ps -eo vsz,state | grep -v Z | awk '{p[$1==0]++} END {printf "%-16s %6d\n%-16s %6d\n%-16s %6d\n", "Kernel processes", p[1], "User processes", p[0], "Total processes", p[0]+p[1]}'

Sample output:

Kernel processes    353
User processes       52
Total processes     405

Explanation: I'm using the hack that VSZ=0 processes can be assumed to be kernel processes. So with awk, I evaluate a comparison on VSZ (from ps -eo vsize), whether it equals zero. The result of the comparison will be either a boolean 0 or 1. I make an array p[], and as I run down the list of processes, if it's a kernel process, I increment p[1]++. Otherwise, as user process, I increment p[0]++. After all the incrementing, I label and print the values (i.e. counts) for p[0] and p[1] in the END { } block.

Edit: Updated to filter out processes in zombie (Z) state.

  • I'm using the hack that VSZ=0 processes can be assumed to be kernel processes. – have you not read existing answers before posting which point out that this condition alone is not enough? – Piotr Dobrogost Nov 25 '20 at 12:47
  • Thankls @PiotrDobrogost, I've updated the command to filter out zombie processes. – Joshua Huber Dec 01 '20 at 18:44
0

What you are looking for, my friend, is not ps, but pstree.

First, identify the first kernel process. Its PID is commonly 1 on system without systemd and 2 with systemd.

Then use this command:

$ pstree -p <1 or 2> | grep -o '([0-9]\+)' | grep -o '[0-9]\+'

The selected answer (one with ✅) is using another command:

$ ps --ppid 2 -p 2 --deselect

The problem with this ps command is that it only includes direct children but not all descendants. The pstree command includes all descendants. You can compare and count the output of these two commands (an easy way is using | wc ) to verify.

ssppjj
  • 121
0

I've created psa script for that purpose. Note that it depends on the linechop tool.