58
$ ps | grep django
28006 ttys004    0:01.12 /usr/bin/python bin/django celeryd --beat
51393 ttys005    0:01.45 /usr/bin/python bin/django celeryd -l INFO
51472 ttys005    0:01.29 /usr/bin/python bin/django celeryd -l INFO
51510 ttys005    0:01.89 /usr/bin/python bin/django celeryd -l INFO
51801 ttys005    0:01.83 /usr/bin/python bin/django celeryd -l INFO
53470 ttys005    0:03.97 /usr/bin/python bin/django celeryd -l INFO
53780 ttys005    0:00.00 grep django

Is there a way to prevent the last process (that is, the grep that was started at the same time as my ps command) being reported?

(I started trying to come up with a regex that would match the literal but not match itself, but that seemed, um, not the right approach...)

7 Answers 7

19

My answer is a variation on the typical answer for searching for "foobar" in a ps listing. The argument of "-A" "ps" is more portable than "aux", I believe, but this change is irrelevant to the answer. The typical answer looks like this:

$ ps -A -ww | grep [f]oobar

Instead I use this pattern:

$ ps -A -ww | grep [^]]foobar

The main advantage is that it's easier to write scripts based on this patterns because you simply concatenate a static string [^]] with whatever pattern you are looking for. You don't need to strip off the first letter of the string then insert it between the square braces and then concatenate the that back together again. When scripting in shell it's easier to simply stick [^]] in front of the pattern you were lookginfor looking for. String slicing in Bash is an ugly thing, so my variation avoids that. This variation says show the lines where the pattern matches WITHOUT a leading right-square-bracket ]. Since the search pattern to exclude a square bracket actually adds the square bracket to the pattern then it will never match itself.

So you could write a portable psgrep command as follows. Here, I make some allowance for differences between Linux, OS X BSD, and others. This adds the column headers from ps, provides a more custom ps format that suits my needs betters, and displays processes listing extra, extra wide so that none of the command-line arguments are missed. Well, most are not missed. Java being Java, it often does things in the worst possible way, so you some java services will run past the maximum allowed length of arguments that the process table will keep track of. I believe this is 1024 characters. The command-lone length allowed to start a process is much longer, but the kernel process table doesn't bother to keep track of anything over 1K in length. Once the command is started the command-name and argument list isn't needed against, so what gets stored in the process table is just informational.

psgrep ()
{
    pattern=[^]]${1};
    case "$(uname -s)" in
        Darwin)
            ps -A -ww -o pid,ppid,nice,pri,pcpu,pmem,etime,user,wchan,stat,command | grep -i -e "^[[:space:]]*PID" -e ${pattern}
        ;;
        Linux)
            ps -A -ww -o pid,ppid,tid,nice,pri,pcpu,pmem,etime,user,wchan:20,stat,command | grep -i -e "^[[:space:]]*PID" -e ${pattern}
        ;;
        *)  # other UNIX flavors get a minimalist version.
            ps -A -ww | grep -i -e ${pattern}
        ;;
    esac
}
1
  • Disadvantage is that this will actually match one char more (in front) than the original pattern. For exemple, this will never match the PID. And can be a bit misleading when used with grep --colour.
    – Læti
    Sep 19, 2018 at 19:31
68

+1 for @jamzed terse answer, however the OP might need some explanation:

ps | grep "[d]jango"

Using that regex you are launching a process which its ps string will not match itself, since the regexp matches "django" and not "[d]jango". That way you'll exclude the process that has the string "[d]jango" which in this case is grep; The same can be applied to pgrep, egrep, awk, sed, etc... whichever command you used to define the regex.

From man 7 regex

   A bracket expression is a list of characters enclosed in "[]".  It nor‐
   mally matches any single character from the list (but see  below).   If
   the  list  begins  with  '^',  it matches any single character (but see
   below) not from the rest of the list.  If two characters  in  the  list
   are  separated  by '-', this is shorthand for the full range of charac‐
   ters between those two (inclusive) in the collating sequence, for exam‐
   ple,  "[0-9]" in ASCII matches any decimal digit.  It is illegal(!) for
   two ranges to share an endpoint, for example, "a-c-e".  Ranges are very
   collating-sequence-dependent,  and portable programs should avoid rely‐
   ing on them.
5
  • 2
    Cool. I'm actually pretty comfortable with regexs but couldn't immediately think of a way to prevent the regexp matching itself. Enclosing a letter in square brackets makes perfect sense. (Including something like [^!] would also work...) Mar 9, 2012 at 11:23
  • 1
    That's nice and crafty.
    – ash
    Mar 9, 2012 at 21:09
  • For the 'ps' specific case, I use '[ ]' at the front of the process name I am searching for. Then I don't need to parse the process name specially for the regex, but it still matches.
    – Relefant
    Nov 5, 2014 at 11:05
  • @hmontoliu It does not work for example: ps aux | grep [s]cript1. Could you help to comment about the solution ?
    – SOUser
    Nov 13, 2017 at 14:05
  • @hmontoliu My fault. It seems the line is shown because of the previous searches...
    – SOUser
    Nov 13, 2017 at 14:09
31

ps | grep [d]jango

ps | grep d[j]ango

...

ps | grep djang[o]

3
  • Add space if you need to grep one char: ps aux| grep "[Z] "
    – A.D.
    Jun 5, 2015 at 12:12
  • @jamzed It does not work for example: ps aux | grep [s]cript1 or ps aux | grep [s]cript2. The grep line is still shown. Could you help to comment about the solution ?
    – SOUser
    Nov 13, 2017 at 14:05
  • @jamzed My fault. It seems the line is shown because of the previous searches...
    – SOUser
    Nov 13, 2017 at 14:09
19

Use pgrep instead: pgrep -lf django

4
  • As usual I forgot to mention the platform (OS X in this case). Presumably pgrep works on various linuxes. Mar 9, 2012 at 11:30
  • I don't agree, @ramruma . I came to this thread precisely because pgrepgives me exactly this problem. But I must say I am testing it in CygWin (where ps can not show the full command line of the process). Apr 4, 2014 at 2:28
  • The manual states "The running pgrep or pkill process will never report itself as a match.", and indeed I've not seen it do so.
    – deltab
    Mar 7, 2016 at 2:07
  • I've just been dealing with a problem where I thought pgrep was matching itself. Turns out it was matching the name of the bash script file I was running it from. Adding -x fixed it, then it does an exact match on the command name. Mar 14, 2019 at 10:43
11

Oh wait, this works:

ps | grep django | grep -v grep
1
  • 7
    Only if the process command line doesn't legitimately include grep, which you cannot count on in the general case.
    – user
    Mar 9, 2012 at 12:41
8

ps -d | grep django

from man ps:

 -d                  Lists information  about  all  processes
                     except session leaders.
5
  • still shows grep on mine...
    – Kevin
    Jun 23, 2013 at 21:03
  • Yep, that works for me on OS X. Jan 29, 2014 at 5:54
  • Doesn't work so well on Linux.
    – Asclepius
    Aug 18, 2014 at 21:55
  • More generally, the options to ps are notoriously non-portable, so without information about which platform this is for, this answer isn't very helpful. Furthermore, this is obviously not adequate when you are not sure that the process you are looking for is not a process leader (i.e. this may help if your target is a daemon, but not generally otherwise).
    – tripleee
    Apr 5, 2016 at 11:51
  • Funny, on Mac this seems to only show the grep process and filters everything else out. Nov 9, 2018 at 22:50
2

This only occurs to me when running inside an ssh "script" command or when using remote management tools. I don't like the hackiness of the previous solutions. I'm not sure if what I've come up with is better but here you go:

| grep -v $$

$$ is replaced by the PID of the ps/pgrep "process" and -v tells grep to not print it.

demo:

watch date &
bash -c 'echo; pgrep -lfa watch | grep -v $$'

the bash -c and the echo are only needed to simulate the mentioned situation and because otherwise pgrep would not report itself.

2
  • What is watch meant to do in this context? Aug 11, 2021 at 23:19
  • it is just used as a demo process, running in the background, to search for.
    – pt1997
    Aug 12, 2021 at 6:48

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.