views:

1723

answers:

10

Is there any bash command that will let you get the nth line of STDOUT?

That is to say, something that would take this

$ ls -l
-rw-r--r--@ 1 root  wheel my.txt
-rw-r--r--@ 1 root  wheel files.txt
-rw-r--r--@ 1 root  wheel here.txt

and do something like

$ ls -l | magic-command 2
-rw-r--r--@ 1 root  wheel files.txt

I realize this would be bad practice when writing scripts meant to be reused, BUT when working with the shell day to day it'd be useful to me to be able to filter my STDOUT in such a way.

I also realize this would be semi-trivial command to write (buffer STDOUT, return a specific line), but I want to know if there's some standard shell command to do this that would be available without me dropping a script into place.

+10  A: 
ls -l | head -2 | tail -1
mobrule
+2, but I'd suggest `head -n 2 | tail -n 1` — modern heads and tails tend to issue warnings otherwise.
Michael Krelin - hacker
OMG, what did I mean by `+2`? ;-)
Michael Krelin - hacker
Using two processes to filter the data is a bit of overkill (but, given the power of machines these days, they'd probably cope). Generalizing to handle one range is not wholly trivial (for range N..M, you use `head -n M | tail -n M-N+1`), and generalizing to handle multiple ranges is not possible.
Jonathan Leffler
head piped into tail? horrible. Multiple better ways to do it.
camh
Great thing about *nix command line: a million and one ways to do everything and everybody's got a favorite and a hates all the other ways... :-)
beggs
+1  A: 

Is Perl easily available to you?

$ perl -n -e 'if ($. == 7) { print; exit(0); }'

Obviously substitute whatever number you want for 7.

catfood
+6  A: 

Alternative to the nice head / tail way:

ls -al | awk '{ if (NR==2) print $0 }'

or

ls -al | sed -n '2p'
ChristopheD
mine awk is better, but sed is nice.
Michael Krelin - hacker
No need for an "if" - see hacker's answer (except for the part about finding *every* file on the system). ;-)
Dennis Williamson
Dennis, completeness!
Michael Krelin - hacker
+3  A: 

For the sake of completeness ;-)

shorter code:

find / | awk NR==3

shorter life:

find / | awk 'NR==3 {print $0; exit}'

Michael Krelin - hacker
You're not kidding about completeness!
Dennis Williamson
I am not ;-) Actually, I don' know why everyone's using `ls` — the original question was about someone's `STDOUT`, so I thought it's better to have it bigger.
Michael Krelin - hacker
At least with GNU awk, the default action is `{ print $0 }`, so `awk 'NR==3' is a shorter way to write the same.
ephemient
You should probably add "; exit" to that action. No point processing the rest of the lines when you're not going to do anything with them.
camh
@camh: See Jonathan Leffer's answer about that: "may generate a SIGPIPE in the feeding process, which may in turn generate an unwanted error message".
ephemient
Thanks, both of you!
Michael Krelin - hacker
@hacker: everyone is using 'ls' as the feeder because the question asks about the magic command in 'ls -l | magic-command'. There isn't a particular excuse to 'find', though it is hardly 'wrong' to do so.
Jonathan Leffler
The question is about *any bash command that will let you get the nth line of STDOUT* (where `STDOUT` means `STDIN`, I think ;-)) `ls` was just an example. Never thought about it as a part of the number at all.
Michael Krelin - hacker
damn, speaking while typing. not "number" - "answer" ;-)
Michael Krelin - hacker
+4  A: 

Try this sed version:

ls -l | sed '2 ! d'

It says "delete all the lines that aren't the second one".

Dennis Williamson
+14  A: 

Using sed, just for variety:

ls -l | sed -n 2p

Using this alternative, which looks more efficient since it stops reading the input when the required line is printed, may generate a SIGPIPE in the feeding process, which may in turn generate an unwanted error message:

ls -l | sed -n -e '2{p;q}'

I've seen that often enough that I usually use the first (which is easier to type, anyway), though ls is not a command that complains when it gets SIGPIPE.

For a range of lines:

ls -l | sed -n 2,4p

For several ranges of lines:

ls -l | sed -n -e 2,4p -e 20,30p
ls -l | sed -n -e '2,4p;20,30p'
Jonathan Leffler
A: 

For more completeness..

ls -l | (for ((x=0;x<2;x++)) ; do read ; done ; head -n1)

Throw away lines until you get to the second, then print out the first line after that. So, it prints the 3rd line.

If it's just the second line..

ls -l | (read; head -n1)

Put as many 'read's as necessary.

Shin
A: 

You can use awk:

ls -l | awk 'NR==2'
Hai Vu
A: 

Yes, the most efficient way (as already pointed out by Jonathan Leffler) is to use sed with print & quit:

set -o pipefail                        # cf. help set
time -p ls -l | sed -n -e '2{p;q;}'    # only print the second line & quit (on Mac OS X)
echo "$?: ${PIPESTATUS[*]}"            # cf. man bash | less -p 'PIPESTATUS'
A: 

From sed1line:

# print line number 52
sed -n '52p'                 # method 1
sed '52!d'                   # method 2
sed '52q;d'                  # method 3, efficient on large files

From awk1line:

# print line number 52
awk 'NR==52'
awk 'NR==52 {print;exit}'          # more efficient on large files
Mark Edgar