191

When I check list of processes and 'grep' out those that are interesting for me, the grep itself is also included in the results. For example, to list terminals:

$ ps aux  | grep terminal
user  2064  0.0  0.6 181452 26460 ?        Sl   Feb13   5:41 gnome-terminal --working-directory=..
user  2979  0.0  0.0   4192   796 pts/3    S+   11:07   0:00 grep --color=auto terminal

Normally I use ps aux | grep something | grep -v grep to get rid of the last entry... but it is not elegant :)

Do you have a more elegant hack to solve this issue (apart of wrapping all the command into a separate script, which is also not bad)

Jakub M.
  • 32,471
  • 48
  • 110
  • 179
  • 4
    For what it's worth, this is an ancient FAQ. See item 3.10 at http://www.faqs.org/faqs/unix-faq/faq/part3/ – tripleee May 16 '13 at 18:33
  • 1
    Thanks for reference. That's their method: `ps ux | awk '/name/ && !/awk/ {print $2}'` – Jakub M. May 16 '13 at 19:55
  • What is the `grep -v grep` part doing? – Jwan622 Apr 21 '17 at 00:10
  • 2
    @Jwan622 `grep -v grep` excludes `grep` from grep results. If grep is used in combination with ps, then grep process (with grep arguments) will be shown as well, cluttering your results. grep -v grep is a common way to avoid that – Eugene Platonov Apr 29 '17 at 03:10

9 Answers9

291

The usual technique is this:

ps aux | egrep '[t]erminal'

This will match lines containing terminal, which egrep '[t]erminal' does not! It also works on many flavours of Unix.

johnsyweb
  • 136,902
  • 23
  • 188
  • 247
  • 1
    This works for me for an arbitrary string, but not for a username, e.g. `ps aux | grep '[r]oot'` . Does anyone know why? – kxsong Oct 01 '14 at 19:41
  • 2
    @kxsong: `| grep '[t]erminal'` selects any line containing the word 'terminal' without putting the word 'terminal' into the process list. What are you trying to achieve with `| grep '[r]oot'` and how is it not working? There is likely to be a better solution. – johnsyweb Oct 01 '14 at 20:33
  • 3
    Correct me if I am wrong, but this also should work on any position of the grepped character: ps aux| grep "te[r]minal" – meso_2600 Mar 23 '16 at 09:54
  • 2
    brilliant hack (I think I should call it that, since the aux / grep authors probably did not think of this scenario.) – Michahell Apr 12 '16 at 14:12
  • Would you please explain how this works? I understand regular expressions, but I don't see how putting t in a character class excludes the grep process itself. – JamieJag May 09 '16 at 11:05
  • 2
    @JamieJag: Well... like I said in my post, `grep '[t]erminal'` will match lines containing `terminal`. The output from `ps aux` will have a line with `grep '[t]erminal'` (with the square brackets), which does not contain the string `terminal` (without the same). – johnsyweb May 09 '16 at 23:41
  • @MichaelTrouw:I'm pretty sure this hack is quite old (I think I remember seing it mentionned in some Usenet faq, back in the "old days" (circa 95? which is not at all around the creation of grep, but that hack may be quite older too) – Olivier Dulac Mar 15 '18 at 16:52
60

Use pgrep. It's more reliable.

doubleDown
  • 8,048
  • 1
  • 32
  • 48
DarkDust
  • 90,870
  • 19
  • 190
  • 224
  • `pgrep` wont work if I look for example for `ps aux | grep 'ssh options'` – Jakub M. Feb 21 '12 at 11:26
  • 12
    Jakub M.: What about `pgrep -f` ? – hillu Sep 30 '13 at 08:26
  • 4
    @jakub-m By default `pgrep` only matches the pattern against the process name. To match against the entire command, use the `-f` flag. – bluecollarcoder Mar 21 '14 at 21:52
  • I have posted an [answer](http://stackoverflow.com/a/25372044/832230) which builds upon this answer, combining `pgrep` with `ps`. – Asclepius Aug 19 '14 at 16:49
  • Note if you prefix pgrep with sudo it does not filter itself out. – codingFoo Dec 03 '15 at 20:57
  • 3
    `pgrep` only returns process IDs. – Melab Dec 15 '15 at 18:11
  • @Melab nope, you can get the full command line with `pgrep -a`. – Desty Jul 29 '16 at 14:39
  • @Desty Older versions of pgrep do not have the '-a' option. – ZaSter Mar 10 '17 at 21:39
  • 1
    older versions took `pgrep -fl` (but couldn't see full cmdline without `-f` matching full cmdline, details: https://serverfault.com/a/619788/44183). But yes if you need any other info beside pid, cmdline, you need `ps`. Can combine them: `ps -p $(pgrep -f foo)` – Beni Cherniavsky-Paskin Jul 30 '17 at 09:00
  • What if I wan't to grep using more than just first [15 characters](https://linux.die.net/man/1/pgrep) of the process name (not path nor arguments)? In that case pgrep became useless. `-f` use the full command line used, not just the real complete name. – Pablo Bianchi Mar 06 '18 at 01:51
29

This answer builds upon a prior pgrep answer. It also builds upon another answer combining the use of ps with pgrep. Here are some pertinent training examples:

$ pgrep -lf sshd
1902 sshd

$ pgrep -f sshd
1902

$ ps up $(pgrep -f sshd)
USER       PID %CPU %MEM    VSZ   RSS TTY      STAT START   TIME COMMAND
root      1902  0.0  0.1  82560  3580 ?        Ss   Oct20   0:00 /usr/sbin/sshd -D

$ ps up $(pgrep -f sshddd)
error: list of process IDs must follow p
[stderr output truncated]

$ ps up $(pgrep -f sshddd) 2>&-
[no output]

The above can be used as a function:

$ psgrep() { ps up $(pgrep -f $@) 2>&-; }

$ psgrep sshd
USER       PID %CPU %MEM    VSZ   RSS TTY      STAT START   TIME COMMAND
root      1902  0.0  0.1  82560  3580 ?        Ss   Oct20   0:00 /usr/sbin/sshd -D

Compare with using ps with grep. The useful header row is not printed:

$  ps aux | grep [s]shd
root      1902  0.0  0.1  82560  3580 ?        Ss   Oct20   0:00 /usr/sbin/sshd -D
Asclepius
  • 57,944
  • 17
  • 167
  • 143
10

You can filter in the ps command, e.g.

ps u -C gnome-terminal

(or search through /proc with find etc.)

Andreas Frische
  • 8,551
  • 2
  • 19
  • 27
  • 1
    Note that this works with GNU's ps (Linux), but not with the BSD ps. – Josh Feb 05 '13 at 23:06
  • This is incorrect even with GNU ps. `ps -C ` will match the exact command. When used with the `a` or `x` options it will report all processes, because `a` and `x` list processes _in addition_ to the set of processes matched by other means. – Animism Dec 12 '13 at 22:19
  • This works only if the process name is specified exactly. It doesn't work for a partial match, e.g. `logind` for `systemd-logind`, or to match arguments. – Asclepius Oct 21 '16 at 05:31
6

One more alternative:

ps -fC terminal

Here the options:

 -f        does full-format listing. This option can be combined
           with many other UNIX-style options to add additional
           columns. It also causes the command arguments to be
           printed. When used with -L, the NLWP (number of
           threads) and LWP (thread ID) columns will be added. See
           the c option, the format keyword args, and the format
           keyword comm.

 -C cmdlist     Select by command name.
                This selects the processes whose executable name is
                given in cmdlist.
TaXXoR
  • 127
  • 1
  • 5
  • 6
    A minor drawback, and one which isn't really related to OP's question, is that this won't show you things like Tomcat, which is actually run as java with a laundry list of arguments. – Charles Wood Dec 30 '13 at 23:25
  • `-C` option was already suggested in @Andreas Frishe's answer posted over year and a half earlier… – Piotr Dobrogost Oct 09 '17 at 12:47
5

Disclaimer: I'm the author of this tool, but...

I'd use px:

~ $ px atom
  PID COMMAND          USERNAME   CPU RAM COMMANDLINE
14321 crashpad_handler walles   0.01s  0% /Users/walles/Downloads/Atom.app/Contents/Frameworks/Electron Framework.framework/Resources/crashpad_handler --database=
16575 crashpad_handler walles   0.01s  0% /Users/walles/Downloads/Atom.app/Contents/Frameworks/Electron Framework.framework/Resources/crashpad_handler --database=
16573 Atom Helper      walles    0.5s  0% /Users/walles/Downloads/Atom.app/Contents/Frameworks/Atom Helper.app/Contents/MacOS/Atom Helper --type=gpu-process --cha
16569 Atom             walles   2.84s  1% /Users/walles/Downloads/Atom.app/Contents/MacOS/Atom --executed-from=/Users/walles/src/goworkspace/src/github.com/github
16591 Atom Helper      walles   7.96s  2% /Users/walles/Downloads/Atom.app/Contents/Frameworks/Atom Helper.app/Contents/MacOS/Atom Helper --type=renderer --no-san

Except for finding processes with a sensible command line interface it also does a lot of other useful things, more details on the project page.

Works on Linux and OS X, easily installed:

curl -Ls https://github.com/walles/px/raw/python/install.sh | bash
Johan Walles
  • 1,447
  • 2
  • 15
  • 23
3

Using brackets to surround a character in the search pattern excludes the grep process since it doesn't contain the matching regex.

$ ps ax | grep 'syslogd'
   16   ??  Ss     0:09.43 /usr/sbin/syslogd
18108 s001  S+     0:00.00 grep syslogd

$ ps ax | grep '[s]yslogd'
   16   ??  Ss     0:09.43 /usr/sbin/syslogd

$ ps ax | grep '[s]yslogd|grep'
   16   ??  Ss     0:09.43 /usr/sbin/syslogd
18144 s001  S+     0:00.00 grep [s]yslogd|grep
Willem Van Onsem
  • 443,496
  • 30
  • 428
  • 555
0

Depending on the ultimate use case, you often want to prefer Awk instead.

ps aux | awk '/[t]erminal/'

This is particularly true when you have something like

ps aux | grep '[t]erminal' | awk '{print $1}'  # useless use of grep!

where obviously the regex can be factored into the Awk script trivially:

ps aux | awk '/[t]erminal/ { print $1 }'

But really, don't reinvent this yourself. pgrep and friends have been around for a long time and handle this entire problem space much better than most ad hoc reimplementations.

tripleee
  • 175,061
  • 34
  • 275
  • 318
-3

Another option is to edit your .bash_profile (or other file that you keep bash aliases in) to create a function that greps 'grep' out of the results.

function mygrep {
grep -v grep | grep --color=auto $1
}

alias grep='mygrep'

The grep -v grep has to be first otherwise your --color=auto won't work for some reason.

This works if you're using bash; if you're using a different shell YMMV.

Toby Speight
  • 27,591
  • 48
  • 66
  • 103
  • 1
    What's with the alias *and* the function? Just do `function grep { command grep -v grep | command grep --color=auto "$@"; }` (also note the fix of the argument and the quoting). However, this is broken in that any non-`ps` invocation of `grep` will no longer work (the arguments are passed incorrectly). Anyway, a much more useful function would be one which modifies the regex to make it not match itself, rather than filter out `grep` from the `grep` results separately. And of course, inventing new solutions to a problem which was adequately solved decades ago is not very productive. – tripleee Oct 02 '15 at 04:25