The complexity required by these answers shows how the Unix philosophy of "do one thing and do it well" sometimes fails us when measured by the yard stick of usability: knowing all these commands well enough to apply them to this common problem (filtering process info and still seeing the column labels) shows the downside of the approach: sometimes things don't fit together very cleanly. This is why tools like ack are so useful, and why perl rocketed past sed,awk, etc. in popularity: it's important for the parts to sum up into a coherent whole.
– iconoclastSep 12 '12 at 19:56

3

of course, for this particular example, you could use the -C argument to ps and you wouldn't need to pipe it into grep. e.g. ps u -C someApp or even ps u -C app1 -C app2 -C app3
– casSep 13 '12 at 6:06

1

@iconoclast: of course the Unixy solution would be a tool that can multiplex multiple lines each to be filtered through different set of filters. Kinda a generalized version of ps aux | { head -1; grep foo; } mentioned by @Nahuel Fouilleul below (his is probably the only solution that I'd be able to recall on the spot if needed)
– Lie RyanSep 13 '12 at 17:13

@iconoclast: Lacking experience with, and knowledge of the tools, what the tools really do well will always seem entirely useless. Knowing a command well is no where on the yard stick of usability, it's on the yard stick of read the fine manual and practice. These tools have been around for decades. They work and fit together very nicely (and cleanly).
– Ярослав РахматуллинSep 15 '12 at 11:19

@ЯрославРахматуллин: I think you may have completely misunderstood what I said. (Perhaps because English is not your first language?) "Usability" is related to UX ("user experience") not utility (or "usefulness"). Pointing out that when a simple operation is this complex it hurts usability is NOT the same as saying the tools are useless. Quite obviously they are not useless. No one in their right mind would say they are useless.
– iconoclastSep 17 '12 at 2:47

15 Answers
15

Good way

Normally you can't do this with grep but you can use other tools. AWK was already mentioned but you can also use sed, like this:

sed -e '1p' -e '/youpattern/!d'

How it works:

Sed utility works on each line individually, running specified commands on each of them. You can have multiple commands, specifying several -e options. We can prepend each command with a range parameter that specifies if this command should be applied to specific line or not.

"1p" is a first command. It uses p command which normally prints all the lines. But we prepend it with a numerical value that specifies the range it should be applied to. Here, we use 1 which means first line. If you want to print more lines, you can use x,yp where x is first line to print, y is last line to print. For example to print first 3 lines, you would use 1,3p

Next command is d which normally deletes all the lines from buffer. Before this command we put yourpattern between two / characters. This is the other way (first was to specify which lines as we did with p command) of addressing lines that the command should be running at. This means the command will only work for the lines that match yourpattern. Except, we use ! character before d command which inverts its logic. So now it will remove all the lines that do not match specified pattern.

At the end, sed will print all the lines that are left in buffer. But we removed lines that do not match from the buffer so only matching lines will be printed.

To sum up: we print 1st line, then we delete all the lines that do not match our pattern from input. Rest of the lines are printed (so only lines that do match the pattern).

First line problem

As mentioned in comments, there is a problem with this approach. If specified pattern matches also first line, it will be printed twice (once by p command and once because of a match). We can avoid this in two ways:

Adding 1d command after 1p. As I already mentioned, d command deletes lines from buffer and we specify it's range by number 1, which means it will only delete 1st line. So the command would be sed -e '1p' -e '1d' -e '/youpattern/!d'

Using 1b command, instead of 1p. It's a trick. b command allows us to jump to other command specified by a label (this way some commands can be omitted). But if this label is not specified (as in our example) it just jumps to the end of commands, ignoring rest of the commands for our line. So in our case, last d command won't remove this line from buffer.

Full example:

ps aux | sed -e '1b' -e '/syslog/!d'

Using semicolon

Some sed implementations can save you some typing by using semicolon to separate commands instead of using multiple -e options. So if you don't care about being portable the command would be ps aux | sed '1b;/syslog/!d'. It works at least in GNU sed and busybox implementations.

Crazy way

Here's, however, rather crazy way to do this with grep. It's definitely not optimal, I'm posting this just for learning purposes, but you may use it for example, if you don't have any other tool in your system:

ps aux | grep -n '.*' | grep -e '\(^1:\)\|syslog'

How it works

First, we use -n option to add line numbers before each line. We want to numerate all the lines we we are matching .* - anything, even empty line. As suggested in comments, we can also match '^', result is the same.

Then we are using extended regular expressions so we can use \| special character which works as OR. So we match if the line starts with 1: (first line) or contains our pattern (in this case its syslog).

Line numbers problem

Now the problem is, we are getting this ugly line numbers in our output. If this is a problem, we can remove them with cut, like this:

ps aux | grep -n '.*' | grep -e '\(^1:\)\|syslog' | cut -d ':' -f2-

-d option specifies delimiter, -f specifies fields (or columns) we want to print. So we want to cut each lines on every : character and print only 2nd and all subsequent columns. This effectively removes first column with it's delimiter and this is exactly what we need.

Line numbering can be done with cat -n as well and would look clearer as with a grep abused for this.
– AlfeSep 12 '12 at 13:34

1

nl does not count empty lines (but prints them without line number), cat -n formats the numbering with preceding spaces, grep -n . strips empty lines at all and adds a colon. All have their ... er ... features ;-)
– AlfeSep 12 '12 at 15:19

2

Very educational well-written answer. I tried to replace "Pretend" (Near the beginning) with "Prepend" for you but it wanted more changes and I didn't feel like changing random crap in your post, so you might want to fix that.
– Bill KSep 12 '12 at 16:57

2

ps aux | sed '1p;/pattern/!d' will print the first line twice if it matches pattern. Best is to used the b command: ps aux | sed -e 1b -e '/pattern/!d'. cat -n is not POSIX. grep -n '^' would number every line (not an issue for ps output which doesn't have empty lines). nl -ba -d $'\n' numbers every line.
– Stéphane ChazelasSep 13 '12 at 9:46

2

Note that 1b;... is not portable nor POSIX, there can't be any other command after "b", so you need a newline or another -e expression.
– Stéphane ChazelasSep 18 '12 at 21:03

That's the idea spelled out directly in bash. I'd like to give more than one thumbs-up for this. I'd just maybe use { IFS='' read line; ... } in case the header starts with spaces.
– AlfeSep 12 '12 at 13:31

I'd just use head -1 instead of the read/echo combo.
– chepnerSep 12 '12 at 16:07

1

Well, it works with head -n1 on my bash. This can probably be implementation specific. My head is not reading whole input in this case, only first line, leaving rest of them in the input buffer.
– Krzysztof AdamskiSep 13 '12 at 10:11

2

head -n1 is shorter, but it appears even the POSIX spec is silent as to how much of its input it is allowed to read, so perhaps read line; echo $line is more portable after all.
– chepnerSep 13 '12 at 11:59

Note however that as long as tee is unable to ignore SIGPIPE signals (see e.g. the discussion here) this approach needs a workaround to be reliable. The workaround is to ignore SIGPIPE signals, this can for example be done like this in bash like shells:

I don't like this solution, primarily because the situation could change between the first and second ps aux call... And if you just want that static first line, why not echo it manually?
– ShadurSep 12 '12 at 11:19

1

Changes between the two calls aren't to be bothered in this situation. The first will only provide the headline which will always fit to the output of the second.
– AlfeSep 12 '12 at 13:30

2

I don't see why this was downvoted, it certainly is a viable option. Upvoting.
– dotancohenSep 12 '12 at 14:37

# print the header (the first line of input)
# and then run the specified command on the body (the rest of the input)
# use it in a pipeline, e.g. ps | body grep somepattern
body() {
IFS= read -r header
printf '%s\n' "$header"
"$@"
}

Thank you. As per the OP, I know some of the text in the line, but not the line number.
– dotancohenMar 23 '16 at 14:46

This pops up as an answer on Google when looking for this use case closely related to the OP, so worth noting here.
– DagelfMar 23 '16 at 15:19

1

If that is the case, then I highly suggest that you start a new question and answer it with this answer. It is perfectly fine to answer your own questions on SE, especially in the situation that you mention. Go ahead and link to your new question in a comment on the OP.
– dotancohenMar 23 '16 at 15:37

There are such questions, but they don't currently pop up on Google.
– DagelfMar 25 '16 at 13:38

Dagelf, bottom line is - your answer doesn't answer the question here. @dotancohen is right - if this pops up as an answer on Google when looking for this use case closely related to the OP then ask a separate question - detailing that closely related use case - and answer it.
– don_crisstiMar 25 '16 at 13:56