8

On CentOS 7.0.1406 I get differing output when running

ps -A -o pid,command | grep [r]esque

than when I run

ps -A -o pid,comm | grep [r]esque

The latter returns nothing; the former what I would expect. I was under the impression that comm was an alias for command. Could someone please explain the difference?

lese
  • 2,726

2 Answers2

9

They are not aliases, command outputs the full command and comm only the command name, so it is possible that the outputs are different. It all depends on what you want to extract the grep command.

An example:

$ ps -A -o pid,command | grep 9600
376 /sbin/agetty --keep-baud 115200 38400 9600 ttyS0 vt220

and the output for the following is empty:

ps -A -o pid,comm | grep 9600

The string 9600 is part of the complete command but the command name.

command, and cmd are aliases to args, with prints the command with all its arguments as string. comm is a different sorting code that prints only the executable name. Manpage snippet:

   args      COMMAND command with all its arguments as a string.

cmd CMD see args. (alias args, command).

comm COMMAND command name (only the executable name).

command COMMAND see args. (alias args, cmd).

Manuel Jordan
  • 1,728
  • 2
  • 16
  • 40
3

On Linux, with the procps(-ng) (at least) implementation of ps (as is the case on CentOS):

  • comm is the process name. That's retrieved from /proc/<pid>/stat and is limited (truncated) to 16 bytes. That's usually the basename of the first argument to the last execve() system call that the process (or any of its ancestors) made, unless it's a kernel thread in which case it's the kernel thread's name like watchdog/0 or rcu_sched or the process has changed it with prctl(PR_SET_NAME). It's the CMD field in the ps output.
  • command aka args is the concatenation of the arguments passed to the latest execve() system call that the process (or any of its ancestors) made. If there was no argument (like for kernel threads), ps uses [process-name] instead (the process name as described above enclosed in square brackets). That's retrieved from /proc/<pid>/cmdline. That's the CMD field in the ps -f output. Note that for scripts, execve() is internally called again after resolution of the she-bang. Processes can also alter that value by overwriting the argv[] strings it received.

POSIX specifies comm (meant to be argv[0]) and args (the arg list as a string, though doesn't say how that list is to be represented (joined with spaces?)), not command. So the procps implementation is not compliant as comm is not the argv[0] there. Solaris, a certified implementation does have argv[0] for comm and has fname for the equivalent of procps' comm (as the CMD column in ps output).

Examples:

  • Relation to execve():

    $ ln -s /bin/sleep very-long-alias-for-sleep
    $ strace -e execve bash -c 'exec -a different-argv0 ./././very-long-alias-for-sleep 12' &
    execve("/bin/bash", ["bash", "-c", "exec -a different-argv0 ./././ve"...], [/* 52 vars */]) = 0                                                  10:56
    execve("/home/stephane/././very-long-alias-for-sleep", ["different-argv0", "12"], [/* 51 vars */]) = 0
    $ ps -o comm,command
    COMMAND         COMMAND
    [...]
    very-long-alias different-argv0 12
    [...]
    
  • perl overwriting both its process name and arg list:

    $ perl -e '$0 = "new name"; system("ps -p $$ -o comm,command")'
    COMMAND         COMMAND
    new name        new name
    
  • Behaviour for scripts:

    $ cat test-script
    #! /bin/sh -e
    ps -o comm,command -p "$$"
    exit
    $ strace -e execve ./test-script arg
    execve("./test-script", ["./test-script", "arg"], [/* 52 vars */]) = 0
    COMMAND         COMMAND
    test-script     /bin/sh -e ./test-script arg
    

    /bin/sh ends up being executed with a different arg list, but the process name remains test-script. Here the argv[0] that sh receives is /bin/sh. On some systems, it's test-script instead.

  • On the note about ancestors:

    $ ((((ps -o pid,comm,command;:);:);:);:)
      PID COMMAND         COMMAND
     4109 zsh             /bin/zsh
    23146 zsh             /bin/zsh
    23147 zsh             /bin/zsh
    23148 zsh             /bin/zsh
    23149 zsh             /bin/zsh
    23150 ps              ps -o pid,comm,command
    

    The 2314{6,7,8,9} processes never executed any command, they inherit their process name and arg list from their parent (4109) which executed /bin/zsh.

    23150 itself initially had a process name of zsh like the others, but it changed to ps upon executing /bin/ps.

  • use -o 'comm' to distinguish threads by their names:

    $ ps -T -o pid,tid,pcpu,bsdtime,comm,command -C firefox.real | sort -k3nr
      # result is sorted by third column '%CPU'
    10743 10743  4.9  14:44 firefox.real    /usr/bin/firefox.real --private-window
    10743 10775  0.3   1:01 Compositor      /usr/bin/firefox.real --private-window
    10743 10750  0.0   0:00 Gecko_IOThread  /usr/bin/firefox.real --private-window
    10743 10751  0.0   0:16 Timer           /usr/bin/firefox.real --private-window
    10743 10752  0.0   0:00 Link Monitor    /usr/bin/firefox.real --private-window
    10743 10753  0.0   0:06 Socket Thread   /usr/bin/firefox.real --private-window
    10743 10755  0.0   0:00 JS Watchdog     /usr/bin/firefox.real --private-window
    10743 10756  0.0   0:04 JS Helper       /usr/bin/firefox.real --private-window
    ...
      PID   TID %CPU   TIME COMMAND         COMMAND
    
zhazha
  • 413
  • What is the -e option used for in #! /bin/sh -e here ? – QuartzCristal Sep 07 '22 at 15:16
  • @QuartzCristal, that's an example of an option passed to the interpreter via the shebang. Here, -e is the same as -o errexit to enable that errexit option. Not particularly useful in that script which only has one command. – Stéphane Chazelas Sep 07 '22 at 15:20
  • Is it that all possible sh programs (shells, I mean) accept the -e option ? If not all, then the option might not work (beside not being that useful here). – QuartzCristal Sep 07 '22 at 15:25
  • @QuartzCristal, yes -e is from the Bourne shell in the 70s and POSIX, so should be supported by all sh implementations from the last few decades. Here, the point though it to show that -e passed to the second execve() done upon executing the script, so what the option does is not really relevant. – Stéphane Chazelas Sep 07 '22 at 15:40