Issue
I have a problem with a Linux command. I have to put on the output 3, 4 and 5 line of the file /etc/passwd, but I have no idea how to do it. I can print first five line:
head -n 5 /etc/passwd
but I don't know how to remove first two lines or do all from scratch.
Solution
Using sed
:
sed -n '3,5p' /etc/passwd
or
sed -n '3,5p;6q' /etc/passwd
(The second version would quit upon encountering line 6 so it would be efficient for huge files.)
Using awk
:
awk 'NR==3,NR==5' /etc/passwd
or
awk 'NR>=3{print}NR==5{exit}' /etc/passwd
(The second variant quit after printing line 5 so it's more efficient.)
Using perl
:
perl -ne 'print if $.>=3 and $.<=5;' /etc/passwd
or
perl -ne 'print if $.>=3; last if $.>5' /etc/passwd
(The second variant is, again, more efficient.)
For fun, lets time these different approaches on an input of 10 million lines:
$ time seq 10000000 | sed -n '3,5p'
3
4
5
real 0m10.086s
user 0m9.173s
sys 0m0.101s
$ time seq 10000000 | sed -n '3,5p;6q'
3
4
5
real 0m0.012s
user 0m0.010s
sys 0m0.001s
$ time seq 10000000 | awk 'NR==3,NR==5'
3
4
5
real 0m12.906s
user 0m11.475s
sys 0m0.134s
$ time seq 10000000 | awk 'NR>=3{print}NR==5{exit}'
3
4
5
real 0m0.013s
user 0m0.001s
sys 0m0.010s
$ time seq 10000000 | perl -ne 'print if $.>=3 and $.<=5;'
3
4
5
real 0m15.982s
user 0m14.217s
sys 0m0.179s
$ time seq 10000000 | perl -ne 'print if $.>=3; last if $.>5'
3
4
5
6
real 0m0.013s
user 0m0.000s
sys 0m0.011s
It's evident that quitting in case of large inputs once the desired lines are obtained is much more efficient. On small inputs, the difference would be negligible, though.
Answered By - devnull Answer Checked By - David Marino (WPSolving Volunteer)