ps | grep is broken on FreeBSD


It is true. Even on the latest FreeBSD 11.0 (I checked the source tree).

ps | grep procName can fail.

$(ps -p pid) can fail.

ps itself on a non-interactive shell can fail.

They can fail if procName comes somewhere after 79 characters (e.g. /abc/def/ghi/…/procName).

Or if you’re using ps -o comm= and trying to match against a command line, it can fail if the command line became too long.

79 ought to be enough

I looked up the source code for FreeBSD (8.4) ps, and here it is:

/* ... */
else if ((ioctl(STDOUT_FILENO, TIOCGWINSZ, (char *)&ws) == -1 &&
    ioctl(STDERR_FILENO, TIOCGWINSZ, (char *)&ws) == -1 &&
    ioctl(STDIN_FILENO,  TIOCGWINSZ, (char *)&ws) == -1) ||
    ws.ws_col == 0)
        termwidth = 79;

What that’s saying is: if you’re not on a terminal, or if your system is unable to tell us how wide your terminal is, then we’ll assume your terminal is 79 characters wide!

I wrote a program to test when the ioctl() above returns non-zero. It does if:

  • You’re piping ps to another program, say grep
  • You’re running a non-interactive shell (e.g. over ssh: Ansible!)

Shouldn’t we assume unlimited width, if we’re not really writing to a terminal? Go figure.

The fix

Anyway, the fix is: Use the -w option. TWICE. So it is actually: -ww. Unless you want your terminal to only go up from 79 to 131 characters. I’m not kidding!

    case 'w':
        if (wflag)
            termwidth = UNLIMITED;
        else if (termwidth < 131)
            termwidth = 131;
        wflag++;
        break;

So, please use: ps -ww | grep procName. Thank you.

What about Linux and Mac?

Both of these systems behave OK. Linux gets ps from procps, which has this piece of code:

142   if(!isatty(STDOUT_FILENO)) screen_cols = OUTBUF_SIZE;

The ps on Mac works as expected, although the man page says it’s derived from BSD. Did Steve Jobs run into it and then get it fixed? ;-)

Update Feb 16 2017

I’ve filed a defect and also uploaded a patch on FreeBSD’s bug database: BUG217159

Update Mar 5 2017

This has been accepted into mainline FreeBSD code. More info.

ps  grep  freebsd  shell 

See also