[unix] How can I extract a predetermined range of lines from a text file on Unix?

I have a ~23000 line SQL dump containing several databases worth of data. I need to extract a certain section of this file (i.e. the data for a single database) and place it in a new file. I know both the start and end line numbers of the data that I want.

Does anyone know a Unix command (or series of commands) to extract all lines from a file between say line 16224 and 16482 and then redirect them into a new file?

This question is related to unix command-line sed text-processing

The answer is


sed -n '16224,16482p;16483q' filename > newfile

From the sed manual:

p - Print out the pattern space (to the standard output). This command is usually only used in conjunction with the -n command-line option.

n - If auto-print is not disabled, print the pattern space, then, regardless, replace the pattern space with the next line of input. If there is no more input then sed exits without processing any more commands.

q - Exit sed without processing any more commands or input. Note that the current pattern space is printed if auto-print is not disabled with the -n option.

and

Addresses in a sed script can be in any of the following forms:

number Specifying a line number will match only that line in the input.

An address range can be specified by specifying two addresses separated by a comma (,). An address range matches lines starting from where the first address matches, and continues until the second address matches (inclusively).


sed -n '16224,16482 p' orig-data-file > new-file

Where 16224,16482 are the start line number and end line number, inclusive. This is 1-indexed. -n suppresses echoing the input as output, which you clearly don't want; the numbers indicate the range of lines to make the following command operate on; the command p prints out the relevant lines.


sed -n '16224,16482 p' orig-data-file > new-file

Where 16224,16482 are the start line number and end line number, inclusive. This is 1-indexed. -n suppresses echoing the input as output, which you clearly don't want; the numbers indicate the range of lines to make the following command operate on; the command p prints out the relevant lines.


sed -n '16224,16482 p' orig-data-file > new-file

Where 16224,16482 are the start line number and end line number, inclusive. This is 1-indexed. -n suppresses echoing the input as output, which you clearly don't want; the numbers indicate the range of lines to make the following command operate on; the command p prints out the relevant lines.


sed -n '16224,16482 p' orig-data-file > new-file

Where 16224,16482 are the start line number and end line number, inclusive. This is 1-indexed. -n suppresses echoing the input as output, which you clearly don't want; the numbers indicate the range of lines to make the following command operate on; the command p prints out the relevant lines.


sed -n '16224,16482 p' orig-data-file > new-file

Where 16224,16482 are the start line number and end line number, inclusive. This is 1-indexed. -n suppresses echoing the input as output, which you clearly don't want; the numbers indicate the range of lines to make the following command operate on; the command p prints out the relevant lines.


sed -n '16224,16482 p' orig-data-file > new-file

Where 16224,16482 are the start line number and end line number, inclusive. This is 1-indexed. -n suppresses echoing the input as output, which you clearly don't want; the numbers indicate the range of lines to make the following command operate on; the command p prints out the relevant lines.


sed -n '16224,16482 p' orig-data-file > new-file

Where 16224,16482 are the start line number and end line number, inclusive. This is 1-indexed. -n suppresses echoing the input as output, which you clearly don't want; the numbers indicate the range of lines to make the following command operate on; the command p prints out the relevant lines.


sed -n '16224,16482 p' orig-data-file > new-file

Where 16224,16482 are the start line number and end line number, inclusive. This is 1-indexed. -n suppresses echoing the input as output, which you clearly don't want; the numbers indicate the range of lines to make the following command operate on; the command p prints out the relevant lines.


Quite simple using head/tail:

head -16482 in.sql | tail -258 > out.sql

using sed:

sed -n '16224,16482p' in.sql > out.sql

using awk:

awk 'NR>=16224&&NR<=16482' in.sql > out.sql

Quite simple using head/tail:

head -16482 in.sql | tail -258 > out.sql

using sed:

sed -n '16224,16482p' in.sql > out.sql

using awk:

awk 'NR>=16224&&NR<=16482' in.sql > out.sql

Quite simple using head/tail:

head -16482 in.sql | tail -258 > out.sql

using sed:

sed -n '16224,16482p' in.sql > out.sql

using awk:

awk 'NR>=16224&&NR<=16482' in.sql > out.sql

Quite simple using head/tail:

head -16482 in.sql | tail -258 > out.sql

using sed:

sed -n '16224,16482p' in.sql > out.sql

using awk:

awk 'NR>=16224&&NR<=16482' in.sql > out.sql

Quite simple using head/tail:

head -16482 in.sql | tail -258 > out.sql

using sed:

sed -n '16224,16482p' in.sql > out.sql

using awk:

awk 'NR>=16224&&NR<=16482' in.sql > out.sql

Quite simple using head/tail:

head -16482 in.sql | tail -258 > out.sql

using sed:

sed -n '16224,16482p' in.sql > out.sql

using awk:

awk 'NR>=16224&&NR<=16482' in.sql > out.sql

Quite simple using head/tail:

head -16482 in.sql | tail -258 > out.sql

using sed:

sed -n '16224,16482p' in.sql > out.sql

using awk:

awk 'NR>=16224&&NR<=16482' in.sql > out.sql

Quite simple using head/tail:

head -16482 in.sql | tail -258 > out.sql

using sed:

sed -n '16224,16482p' in.sql > out.sql

using awk:

awk 'NR>=16224&&NR<=16482' in.sql > out.sql

You could use 'vi' and then the following command:

:16224,16482w!/tmp/some-file

Alternatively:

cat file | head -n 16482 | tail -n 258

EDIT:- Just to add explanation, you use head -n 16482 to display first 16482 lines then use tail -n 258 to get last 258 lines out of the first output.


You could use 'vi' and then the following command:

:16224,16482w!/tmp/some-file

Alternatively:

cat file | head -n 16482 | tail -n 258

EDIT:- Just to add explanation, you use head -n 16482 to display first 16482 lines then use tail -n 258 to get last 258 lines out of the first output.


You could use 'vi' and then the following command:

:16224,16482w!/tmp/some-file

Alternatively:

cat file | head -n 16482 | tail -n 258

EDIT:- Just to add explanation, you use head -n 16482 to display first 16482 lines then use tail -n 258 to get last 258 lines out of the first output.


You could use 'vi' and then the following command:

:16224,16482w!/tmp/some-file

Alternatively:

cat file | head -n 16482 | tail -n 258

EDIT:- Just to add explanation, you use head -n 16482 to display first 16482 lines then use tail -n 258 to get last 258 lines out of the first output.


You could use 'vi' and then the following command:

:16224,16482w!/tmp/some-file

Alternatively:

cat file | head -n 16482 | tail -n 258

EDIT:- Just to add explanation, you use head -n 16482 to display first 16482 lines then use tail -n 258 to get last 258 lines out of the first output.


You could use 'vi' and then the following command:

:16224,16482w!/tmp/some-file

Alternatively:

cat file | head -n 16482 | tail -n 258

EDIT:- Just to add explanation, you use head -n 16482 to display first 16482 lines then use tail -n 258 to get last 258 lines out of the first output.


You could use 'vi' and then the following command:

:16224,16482w!/tmp/some-file

Alternatively:

cat file | head -n 16482 | tail -n 258

EDIT:- Just to add explanation, you use head -n 16482 to display first 16482 lines then use tail -n 258 to get last 258 lines out of the first output.


You could use 'vi' and then the following command:

:16224,16482w!/tmp/some-file

Alternatively:

cat file | head -n 16482 | tail -n 258

EDIT:- Just to add explanation, you use head -n 16482 to display first 16482 lines then use tail -n 258 to get last 258 lines out of the first output.


There is another approach with awk:

awk 'NR==16224, NR==16482' file

If the file is huge, it can be good to exit after reading the last desired line. This way, it won't read the following lines unnecessarily:

awk 'NR==16224, NR==16482-1; NR==16482 {print; exit}' file

awk 'NR==16224, NR==16482; NR==16482 {exit}' file

There is another approach with awk:

awk 'NR==16224, NR==16482' file

If the file is huge, it can be good to exit after reading the last desired line. This way, it won't read the following lines unnecessarily:

awk 'NR==16224, NR==16482-1; NR==16482 {print; exit}' file

awk 'NR==16224, NR==16482; NR==16482 {exit}' file

There is another approach with awk:

awk 'NR==16224, NR==16482' file

If the file is huge, it can be good to exit after reading the last desired line. This way, it won't read the following lines unnecessarily:

awk 'NR==16224, NR==16482-1; NR==16482 {print; exit}' file

awk 'NR==16224, NR==16482; NR==16482 {exit}' file

There is another approach with awk:

awk 'NR==16224, NR==16482' file

If the file is huge, it can be good to exit after reading the last desired line. This way, it won't read the following lines unnecessarily:

awk 'NR==16224, NR==16482-1; NR==16482 {print; exit}' file

awk 'NR==16224, NR==16482; NR==16482 {exit}' file

perl -ne 'print if 16224..16482' file.txt > new_file.txt

perl -ne 'print if 16224..16482' file.txt > new_file.txt

perl -ne 'print if 16224..16482' file.txt > new_file.txt

perl -ne 'print if 16224..16482' file.txt > new_file.txt

perl -ne 'print if 16224..16482' file.txt > new_file.txt

perl -ne 'print if 16224..16482' file.txt > new_file.txt

perl -ne 'print if 16224..16482' file.txt > new_file.txt

perl -ne 'print if 16224..16482' file.txt > new_file.txt

 # print section of file based on line numbers
 sed -n '16224 ,16482p'               # method 1
 sed '16224,16482!d'                 # method 2

 # print section of file based on line numbers
 sed -n '16224 ,16482p'               # method 1
 sed '16224,16482!d'                 # method 2

 # print section of file based on line numbers
 sed -n '16224 ,16482p'               # method 1
 sed '16224,16482!d'                 # method 2

 # print section of file based on line numbers
 sed -n '16224 ,16482p'               # method 1
 sed '16224,16482!d'                 # method 2

 # print section of file based on line numbers
 sed -n '16224 ,16482p'               # method 1
 sed '16224,16482!d'                 # method 2

 # print section of file based on line numbers
 sed -n '16224 ,16482p'               # method 1
 sed '16224,16482!d'                 # method 2

 # print section of file based on line numbers
 sed -n '16224 ,16482p'               # method 1
 sed '16224,16482!d'                 # method 2

 # print section of file based on line numbers
 sed -n '16224 ,16482p'               # method 1
 sed '16224,16482!d'                 # method 2

Standing on the shoulders of boxxar, I like this:

sed -n '<first line>,$p;<last line>q' input

e.g.

sed -n '16224,$p;16482q' input

The $ means "last line", so the first command makes sed print all lines starting with line 16224 and the second command makes sed quit after printing line 16428. (Adding 1 for the q-range in boxxar's solution does not seem to be necessary.)

I like this variant because I don't need to specify the ending line number twice. And I measured that using $ does not have detrimental effects on performance.


Standing on the shoulders of boxxar, I like this:

sed -n '<first line>,$p;<last line>q' input

e.g.

sed -n '16224,$p;16482q' input

The $ means "last line", so the first command makes sed print all lines starting with line 16224 and the second command makes sed quit after printing line 16428. (Adding 1 for the q-range in boxxar's solution does not seem to be necessary.)

I like this variant because I don't need to specify the ending line number twice. And I measured that using $ does not have detrimental effects on performance.


Standing on the shoulders of boxxar, I like this:

sed -n '<first line>,$p;<last line>q' input

e.g.

sed -n '16224,$p;16482q' input

The $ means "last line", so the first command makes sed print all lines starting with line 16224 and the second command makes sed quit after printing line 16428. (Adding 1 for the q-range in boxxar's solution does not seem to be necessary.)

I like this variant because I don't need to specify the ending line number twice. And I measured that using $ does not have detrimental effects on performance.


Standing on the shoulders of boxxar, I like this:

sed -n '<first line>,$p;<last line>q' input

e.g.

sed -n '16224,$p;16482q' input

The $ means "last line", so the first command makes sed print all lines starting with line 16224 and the second command makes sed quit after printing line 16428. (Adding 1 for the q-range in boxxar's solution does not seem to be necessary.)

I like this variant because I don't need to specify the ending line number twice. And I measured that using $ does not have detrimental effects on performance.


cat dump.txt | head -16224 | tail -258

should do the trick. The downside of this approach is that you need to do the arithmetic to determine the argument for tail and to account for whether you want the 'between' to include the ending line or not.


cat dump.txt | head -16224 | tail -258

should do the trick. The downside of this approach is that you need to do the arithmetic to determine the argument for tail and to account for whether you want the 'between' to include the ending line or not.


cat dump.txt | head -16224 | tail -258

should do the trick. The downside of this approach is that you need to do the arithmetic to determine the argument for tail and to account for whether you want the 'between' to include the ending line or not.


cat dump.txt | head -16224 | tail -258

should do the trick. The downside of this approach is that you need to do the arithmetic to determine the argument for tail and to account for whether you want the 'between' to include the ending line or not.


cat dump.txt | head -16224 | tail -258

should do the trick. The downside of this approach is that you need to do the arithmetic to determine the argument for tail and to account for whether you want the 'between' to include the ending line or not.


cat dump.txt | head -16224 | tail -258

should do the trick. The downside of this approach is that you need to do the arithmetic to determine the argument for tail and to account for whether you want the 'between' to include the ending line or not.


cat dump.txt | head -16224 | tail -258

should do the trick. The downside of this approach is that you need to do the arithmetic to determine the argument for tail and to account for whether you want the 'between' to include the ending line or not.


cat dump.txt | head -16224 | tail -258

should do the trick. The downside of this approach is that you need to do the arithmetic to determine the argument for tail and to account for whether you want the 'between' to include the ending line or not.


sed -n '16224,16482p' < dump.sql


sed -n '16224,16482p' < dump.sql


sed -n '16224,16482p' < dump.sql


sed -n '16224,16482p' < dump.sql


sed -n '16224,16482p' < dump.sql


sed -n '16224,16482p' < dump.sql


sed -n '16224,16482p' < dump.sql


sed -n '16224,16482p' < dump.sql


Even we can do this to check at command line:

cat filename|sed 'n1,n2!d' > abc.txt

For Example:

cat foo.pl|sed '100,200!d' > abc.txt

Even we can do this to check at command line:

cat filename|sed 'n1,n2!d' > abc.txt

For Example:

cat foo.pl|sed '100,200!d' > abc.txt

I wanted to do the same thing from a script using a variable and achieved it by putting quotes around the $variable to separate the variable name from the p:

sed -n "$first","$count"p imagelist.txt >"$imageblock"

I wanted to split a list into separate folders and found the initial question and answer a useful step. (split command not an option on the old os I have to port code to).


I wanted to do the same thing from a script using a variable and achieved it by putting quotes around the $variable to separate the variable name from the p:

sed -n "$first","$count"p imagelist.txt >"$imageblock"

I wanted to split a list into separate folders and found the initial question and answer a useful step. (split command not an option on the old os I have to port code to).


Quick and dirty:

head -16428 < file.in | tail -259 > file.out

Probably not the best way to do it but it should work.

BTW: 259 = 16482-16224+1.


Quick and dirty:

head -16428 < file.in | tail -259 > file.out

Probably not the best way to do it but it should work.

BTW: 259 = 16482-16224+1.


Using ruby:

ruby -ne 'puts "#{$.}: #{$_}" if $. >= 32613500 && $. <= 32614500' < GND.rdf > GND.extract.rdf

Using ruby:

ruby -ne 'puts "#{$.}: #{$_}" if $. >= 32613500 && $. <= 32614500' < GND.rdf > GND.extract.rdf

Quick and dirty:

head -16428 < file.in | tail -259 > file.out

Probably not the best way to do it but it should work.

BTW: 259 = 16482-16224+1.


Quick and dirty:

head -16428 < file.in | tail -259 > file.out

Probably not the best way to do it but it should work.

BTW: 259 = 16482-16224+1.


I wrote a Haskell program called splitter that does exactly this: have a read through my release blog post.

You can use the program as follows:

$ cat somefile | splitter 16224-16482

And that is all that there is to it. You will need Haskell to install it. Just:

$ cabal install splitter

And you are done. I hope that you find this program useful.


I wrote a Haskell program called splitter that does exactly this: have a read through my release blog post.

You can use the program as follows:

$ cat somefile | splitter 16224-16482

And that is all that there is to it. You will need Haskell to install it. Just:

$ cabal install splitter

And you are done. I hope that you find this program useful.


Even we can do this to check at command line:

cat filename|sed 'n1,n2!d' > abc.txt

For Example:

cat foo.pl|sed '100,200!d' > abc.txt

Even we can do this to check at command line:

cat filename|sed 'n1,n2!d' > abc.txt

For Example:

cat foo.pl|sed '100,200!d' > abc.txt

I wanted to do the same thing from a script using a variable and achieved it by putting quotes around the $variable to separate the variable name from the p:

sed -n "$first","$count"p imagelist.txt >"$imageblock"

I wanted to split a list into separate folders and found the initial question and answer a useful step. (split command not an option on the old os I have to port code to).


I wanted to do the same thing from a script using a variable and achieved it by putting quotes around the $variable to separate the variable name from the p:

sed -n "$first","$count"p imagelist.txt >"$imageblock"

I wanted to split a list into separate folders and found the initial question and answer a useful step. (split command not an option on the old os I have to port code to).


Quick and dirty:

head -16428 < file.in | tail -259 > file.out

Probably not the best way to do it but it should work.

BTW: 259 = 16482-16224+1.


Quick and dirty:

head -16428 < file.in | tail -259 > file.out

Probably not the best way to do it but it should work.

BTW: 259 = 16482-16224+1.


Using ruby:

ruby -ne 'puts "#{$.}: #{$_}" if $. >= 32613500 && $. <= 32614500' < GND.rdf > GND.extract.rdf

Using ruby:

ruby -ne 'puts "#{$.}: #{$_}" if $. >= 32613500 && $. <= 32614500' < GND.rdf > GND.extract.rdf

Quick and dirty:

head -16428 < file.in | tail -259 > file.out

Probably not the best way to do it but it should work.

BTW: 259 = 16482-16224+1.


Quick and dirty:

head -16428 < file.in | tail -259 > file.out

Probably not the best way to do it but it should work.

BTW: 259 = 16482-16224+1.


I wrote a Haskell program called splitter that does exactly this: have a read through my release blog post.

You can use the program as follows:

$ cat somefile | splitter 16224-16482

And that is all that there is to it. You will need Haskell to install it. Just:

$ cabal install splitter

And you are done. I hope that you find this program useful.


I wrote a Haskell program called splitter that does exactly this: have a read through my release blog post.

You can use the program as follows:

$ cat somefile | splitter 16224-16482

And that is all that there is to it. You will need Haskell to install it. Just:

$ cabal install splitter

And you are done. I hope that you find this program useful.


I would use:

awk 'FNR >= 16224 && FNR <= 16482' my_file > extracted.txt

FNR contains the record (line) number of the line being read from the file.


I would use:

awk 'FNR >= 16224 && FNR <= 16482' my_file > extracted.txt

FNR contains the record (line) number of the line being read from the file.


Using ed:

ed -s infile <<<'16224,16482p'

-s suppresses diagnostic output; the actual commands are in a here-string. Specifically, 16224,16482p runs the p (print) command on the desired line address range.


Using ed:

ed -s infile <<<'16224,16482p'

-s suppresses diagnostic output; the actual commands are in a here-string. Specifically, 16224,16482p runs the p (print) command on the desired line address range.


I was about to post the head/tail trick, but actually I'd probably just fire up emacs. ;-)

  1. esc-x goto-line ret 16224
  2. mark (ctrl-space)
  3. esc-x goto-line ret 16482
  4. esc-w

open the new output file, ctl-y save

Let's me see what's happening.


I was about to post the head/tail trick, but actually I'd probably just fire up emacs. ;-)

  1. esc-x goto-line ret 16224
  2. mark (ctrl-space)
  3. esc-x goto-line ret 16482
  4. esc-w

open the new output file, ctl-y save

Let's me see what's happening.


I was about to post the head/tail trick, but actually I'd probably just fire up emacs. ;-)

  1. esc-x goto-line ret 16224
  2. mark (ctrl-space)
  3. esc-x goto-line ret 16482
  4. esc-w

open the new output file, ctl-y save

Let's me see what's happening.


I was about to post the head/tail trick, but actually I'd probably just fire up emacs. ;-)

  1. esc-x goto-line ret 16224
  2. mark (ctrl-space)
  3. esc-x goto-line ret 16482
  4. esc-w

open the new output file, ctl-y save

Let's me see what's happening.


I would use:

awk 'FNR >= 16224 && FNR <= 16482' my_file > extracted.txt

FNR contains the record (line) number of the line being read from the file.


I would use:

awk 'FNR >= 16224 && FNR <= 16482' my_file > extracted.txt

FNR contains the record (line) number of the line being read from the file.


Using ed:

ed -s infile <<<'16224,16482p'

-s suppresses diagnostic output; the actual commands are in a here-string. Specifically, 16224,16482p runs the p (print) command on the desired line address range.


Using ed:

ed -s infile <<<'16224,16482p'

-s suppresses diagnostic output; the actual commands are in a here-string. Specifically, 16224,16482p runs the p (print) command on the desired line address range.


I was about to post the head/tail trick, but actually I'd probably just fire up emacs. ;-)

  1. esc-x goto-line ret 16224
  2. mark (ctrl-space)
  3. esc-x goto-line ret 16482
  4. esc-w

open the new output file, ctl-y save

Let's me see what's happening.


I was about to post the head/tail trick, but actually I'd probably just fire up emacs. ;-)

  1. esc-x goto-line ret 16224
  2. mark (ctrl-space)
  3. esc-x goto-line ret 16482
  4. esc-w

open the new output file, ctl-y save

Let's me see what's happening.


I was about to post the head/tail trick, but actually I'd probably just fire up emacs. ;-)

  1. esc-x goto-line ret 16224
  2. mark (ctrl-space)
  3. esc-x goto-line ret 16482
  4. esc-w

open the new output file, ctl-y save

Let's me see what's happening.


I was about to post the head/tail trick, but actually I'd probably just fire up emacs. ;-)

  1. esc-x goto-line ret 16224
  2. mark (ctrl-space)
  3. esc-x goto-line ret 16482
  4. esc-w

open the new output file, ctl-y save

Let's me see what's happening.


I wrote a small bash script that you can run from your command line, so long as you update your PATH to include its directory (or you can place it in a directory that is already contained in the PATH).

Usage: $ pinch filename start-line end-line

#!/bin/bash
# Display line number ranges of a file to the terminal.
# Usage: $ pinch filename start-line end-line
# By Evan J. Coon

FILENAME=$1
START=$2
END=$3

ERROR="[PINCH ERROR]"

# Check that the number of arguments is 3
if [ $# -lt 3 ]; then
    echo "$ERROR Need three arguments: Filename Start-line End-line"
    exit 1
fi

# Check that the file exists.
if [ ! -f "$FILENAME" ]; then
    echo -e "$ERROR File does not exist. \n\t$FILENAME"
    exit 1
fi

# Check that start-line is not greater than end-line
if [ "$START" -gt "$END" ]; then
    echo -e "$ERROR Start line is greater than End line."
    exit 1
fi

# Check that start-line is positive.
if [ "$START" -lt 0 ]; then
    echo -e "$ERROR Start line is less than 0."
    exit 1
fi

# Check that end-line is positive.
if [ "$END" -lt 0 ]; then
    echo -e "$ERROR End line is less than 0."
    exit 1
fi

NUMOFLINES=$(wc -l < "$FILENAME")

# Check that end-line is not greater than the number of lines in the file.
if [ "$END" -gt "$NUMOFLINES" ]; then
    echo -e "$ERROR End line is greater than number of lines in file."
    exit 1
fi

# The distance from the end of the file to end-line
ENDDIFF=$(( NUMOFLINES - END ))

# For larger files, this will run more quickly. If the distance from the
# end of the file to the end-line is less than the distance from the
# start of the file to the start-line, then start pinching from the
# bottom as opposed to the top.
if [ "$START" -lt "$ENDDIFF" ]; then
    < "$FILENAME" head -n $END | tail -n +$START
else
    < "$FILENAME" tail -n +$START | head -n $(( END-START+1 ))
fi

# Success
exit 0

I wrote a small bash script that you can run from your command line, so long as you update your PATH to include its directory (or you can place it in a directory that is already contained in the PATH).

Usage: $ pinch filename start-line end-line

#!/bin/bash
# Display line number ranges of a file to the terminal.
# Usage: $ pinch filename start-line end-line
# By Evan J. Coon

FILENAME=$1
START=$2
END=$3

ERROR="[PINCH ERROR]"

# Check that the number of arguments is 3
if [ $# -lt 3 ]; then
    echo "$ERROR Need three arguments: Filename Start-line End-line"
    exit 1
fi

# Check that the file exists.
if [ ! -f "$FILENAME" ]; then
    echo -e "$ERROR File does not exist. \n\t$FILENAME"
    exit 1
fi

# Check that start-line is not greater than end-line
if [ "$START" -gt "$END" ]; then
    echo -e "$ERROR Start line is greater than End line."
    exit 1
fi

# Check that start-line is positive.
if [ "$START" -lt 0 ]; then
    echo -e "$ERROR Start line is less than 0."
    exit 1
fi

# Check that end-line is positive.
if [ "$END" -lt 0 ]; then
    echo -e "$ERROR End line is less than 0."
    exit 1
fi

NUMOFLINES=$(wc -l < "$FILENAME")

# Check that end-line is not greater than the number of lines in the file.
if [ "$END" -gt "$NUMOFLINES" ]; then
    echo -e "$ERROR End line is greater than number of lines in file."
    exit 1
fi

# The distance from the end of the file to end-line
ENDDIFF=$(( NUMOFLINES - END ))

# For larger files, this will run more quickly. If the distance from the
# end of the file to the end-line is less than the distance from the
# start of the file to the start-line, then start pinching from the
# bottom as opposed to the top.
if [ "$START" -lt "$ENDDIFF" ]; then
    < "$FILENAME" head -n $END | tail -n +$START
else
    < "$FILENAME" tail -n +$START | head -n $(( END-START+1 ))
fi

# Success
exit 0

This might work for you (GNU sed):

sed -ne '16224,16482w newfile' -e '16482q' file

or taking advantage of bash:

sed -n $'16224,16482w newfile\n16482q' file

This might work for you (GNU sed):

sed -ne '16224,16482w newfile' -e '16482q' file

or taking advantage of bash:

sed -n $'16224,16482w newfile\n16482q' file

Just benchmarking 3 solutions given above, that works to me:

  • awk
  • sed
  • "head+tail"

Credits on the 3 solutions goes to:

  • @boxxar
  • @avandeursen
  • @wds
  • @manveru
  • @sibaz
  • @SOFe
  • @fedorqui 'SO stop harming'
  • @Robin A. Meade

I'm using a huge file I find in my server:

# wc fo2debug.1.log
   10421186    19448208 38795491134 fo2debug.1.log

38 Gb in 10.4 million lines.

And yes, I have a logrotate problem. : ))


Make your bets!


Getting 256 lines from the beginning of the file.

# time sed -n '1001,1256p;1256q' fo2debug.1.log | wc -l
256

real    0m0,003s
user    0m0,000s
sys     0m0,004s

# time head -1256 fo2debug.1.log | tail -n +1001 | wc -l
256

real    0m0,003s
user    0m0,006s
sys     0m0,000s

# time awk 'NR==1001, NR==1256; NR==1256 {exit}' fo2debug.1.log | wc -l
256

real    0m0,002s
user    0m0,004s
sys     0m0,000s

Awk won. Technical tie in second place between sed and "head+tail".


Getting 256 lines at the end of the first third of the file.

# time sed -n '3473001,3473256p;3473256q' fo2debug.1.log | wc -l
256

real    0m0,265s
user    0m0,242s
sys     0m0,024s

# time head -3473256 fo2debug.1.log | tail -n +3473001 | wc -l
256

real    0m0,308s
user    0m0,313s
sys     0m0,145s

# time awk 'NR==3473001, NR==3473256; NR==3473256 {exit}' fo2debug.1.log | wc -l
256

real    0m0,393s
user    0m0,326s
sys     0m0,068s

Sed won. Followed by "head+tail" and, finally, awk.


Getting 256 lines at the end of the second third of the file.

# time sed -n '6947001,6947256p;6947256q' fo2debug.1.log | wc -l
A256

real    0m0,525s
user    0m0,462s
sys     0m0,064s

# time head -6947256 fo2debug.1.log | tail -n +6947001 | wc -l
256

real    0m0,615s
user    0m0,488s
sys     0m0,423s

# time awk 'NR==6947001, NR==6947256; NR==6947256 {exit}' fo2debug.1.log | wc -l
256

real    0m0,779s
user    0m0,650s
sys     0m0,130s

Same results.

Sed won. Followed by "head+tail" and, finally, awk.


Getting 256 lines near the end of the file.

# time sed -n '10420001,10420256p;10420256q' fo2debug.1.log | wc -l
256

real    1m50,017s
user    0m12,735s
sys     0m22,926s

# time head -10420256 fo2debug.1.log | tail -n +10420001 | wc -l
256

real    1m48,269s
user    0m42,404s
sys     0m51,015s

# time awk 'NR==10420001, NR==10420256; NR==10420256 {exit}' fo2debug.1.log | wc -l
256

real    1m49,106s
user    0m12,322s
sys     0m18,576s

And suddenly, a twist!

"Head+tail" won. Followed by awk and, finally, sed.


(some hours later...)

Sorry guys!

My analysis above ends up being an example of a basic flaw in doing an analysis.

The flaw is not knowing in depth the resources used for the analysis.

In this case, I used a log file to analyze the performance of a search for a certain number of lines within it.

Using 3 different techniques, searches were made at different points in the file, comparing the performance of the techniques at each point and checking whether the results varied depending on the point in the file where the search was made.

My mistake was to assume that there was a certain homogeneity of content in the log file.

The reality is that long lines appear more frequently at the end of the file.

Thus, the apparent conclusion that longer searches (closer to the end of the file) are better with a given technique, may be biased. In fact, this technique may be better when dealing with longer lines. What remains to be confirmed.


Just benchmarking 3 solutions given above, that works to me:

  • awk
  • sed
  • "head+tail"

Credits on the 3 solutions goes to:

  • @boxxar
  • @avandeursen
  • @wds
  • @manveru
  • @sibaz
  • @SOFe
  • @fedorqui 'SO stop harming'
  • @Robin A. Meade

I'm using a huge file I find in my server:

# wc fo2debug.1.log
   10421186    19448208 38795491134 fo2debug.1.log

38 Gb in 10.4 million lines.

And yes, I have a logrotate problem. : ))


Make your bets!


Getting 256 lines from the beginning of the file.

# time sed -n '1001,1256p;1256q' fo2debug.1.log | wc -l
256

real    0m0,003s
user    0m0,000s
sys     0m0,004s

# time head -1256 fo2debug.1.log | tail -n +1001 | wc -l
256

real    0m0,003s
user    0m0,006s
sys     0m0,000s

# time awk 'NR==1001, NR==1256; NR==1256 {exit}' fo2debug.1.log | wc -l
256

real    0m0,002s
user    0m0,004s
sys     0m0,000s

Awk won. Technical tie in second place between sed and "head+tail".


Getting 256 lines at the end of the first third of the file.

# time sed -n '3473001,3473256p;3473256q' fo2debug.1.log | wc -l
256

real    0m0,265s
user    0m0,242s
sys     0m0,024s

# time head -3473256 fo2debug.1.log | tail -n +3473001 | wc -l
256

real    0m0,308s
user    0m0,313s
sys     0m0,145s

# time awk 'NR==3473001, NR==3473256; NR==3473256 {exit}' fo2debug.1.log | wc -l
256

real    0m0,393s
user    0m0,326s
sys     0m0,068s

Sed won. Followed by "head+tail" and, finally, awk.


Getting 256 lines at the end of the second third of the file.

# time sed -n '6947001,6947256p;6947256q' fo2debug.1.log | wc -l
A256

real    0m0,525s
user    0m0,462s
sys     0m0,064s

# time head -6947256 fo2debug.1.log | tail -n +6947001 | wc -l
256

real    0m0,615s
user    0m0,488s
sys     0m0,423s

# time awk 'NR==6947001, NR==6947256; NR==6947256 {exit}' fo2debug.1.log | wc -l
256

real    0m0,779s
user    0m0,650s
sys     0m0,130s

Same results.

Sed won. Followed by "head+tail" and, finally, awk.


Getting 256 lines near the end of the file.

# time sed -n '10420001,10420256p;10420256q' fo2debug.1.log | wc -l
256

real    1m50,017s
user    0m12,735s
sys     0m22,926s

# time head -10420256 fo2debug.1.log | tail -n +10420001 | wc -l
256

real    1m48,269s
user    0m42,404s
sys     0m51,015s

# time awk 'NR==10420001, NR==10420256; NR==10420256 {exit}' fo2debug.1.log | wc -l
256

real    1m49,106s
user    0m12,322s
sys     0m18,576s

And suddenly, a twist!

"Head+tail" won. Followed by awk and, finally, sed.


(some hours later...)

Sorry guys!

My analysis above ends up being an example of a basic flaw in doing an analysis.

The flaw is not knowing in depth the resources used for the analysis.

In this case, I used a log file to analyze the performance of a search for a certain number of lines within it.

Using 3 different techniques, searches were made at different points in the file, comparing the performance of the techniques at each point and checking whether the results varied depending on the point in the file where the search was made.

My mistake was to assume that there was a certain homogeneity of content in the log file.

The reality is that long lines appear more frequently at the end of the file.

Thus, the apparent conclusion that longer searches (closer to the end of the file) are better with a given technique, may be biased. In fact, this technique may be better when dealing with longer lines. What remains to be confirmed.


I wrote a small bash script that you can run from your command line, so long as you update your PATH to include its directory (or you can place it in a directory that is already contained in the PATH).

Usage: $ pinch filename start-line end-line

#!/bin/bash
# Display line number ranges of a file to the terminal.
# Usage: $ pinch filename start-line end-line
# By Evan J. Coon

FILENAME=$1
START=$2
END=$3

ERROR="[PINCH ERROR]"

# Check that the number of arguments is 3
if [ $# -lt 3 ]; then
    echo "$ERROR Need three arguments: Filename Start-line End-line"
    exit 1
fi

# Check that the file exists.
if [ ! -f "$FILENAME" ]; then
    echo -e "$ERROR File does not exist. \n\t$FILENAME"
    exit 1
fi

# Check that start-line is not greater than end-line
if [ "$START" -gt "$END" ]; then
    echo -e "$ERROR Start line is greater than End line."
    exit 1
fi

# Check that start-line is positive.
if [ "$START" -lt 0 ]; then
    echo -e "$ERROR Start line is less than 0."
    exit 1
fi

# Check that end-line is positive.
if [ "$END" -lt 0 ]; then
    echo -e "$ERROR End line is less than 0."
    exit 1
fi

NUMOFLINES=$(wc -l < "$FILENAME")

# Check that end-line is not greater than the number of lines in the file.
if [ "$END" -gt "$NUMOFLINES" ]; then
    echo -e "$ERROR End line is greater than number of lines in file."
    exit 1
fi

# The distance from the end of the file to end-line
ENDDIFF=$(( NUMOFLINES - END ))

# For larger files, this will run more quickly. If the distance from the
# end of the file to the end-line is less than the distance from the
# start of the file to the start-line, then start pinching from the
# bottom as opposed to the top.
if [ "$START" -lt "$ENDDIFF" ]; then
    < "$FILENAME" head -n $END | tail -n +$START
else
    < "$FILENAME" tail -n +$START | head -n $(( END-START+1 ))
fi

# Success
exit 0

I wrote a small bash script that you can run from your command line, so long as you update your PATH to include its directory (or you can place it in a directory that is already contained in the PATH).

Usage: $ pinch filename start-line end-line

#!/bin/bash
# Display line number ranges of a file to the terminal.
# Usage: $ pinch filename start-line end-line
# By Evan J. Coon

FILENAME=$1
START=$2
END=$3

ERROR="[PINCH ERROR]"

# Check that the number of arguments is 3
if [ $# -lt 3 ]; then
    echo "$ERROR Need three arguments: Filename Start-line End-line"
    exit 1
fi

# Check that the file exists.
if [ ! -f "$FILENAME" ]; then
    echo -e "$ERROR File does not exist. \n\t$FILENAME"
    exit 1
fi

# Check that start-line is not greater than end-line
if [ "$START" -gt "$END" ]; then
    echo -e "$ERROR Start line is greater than End line."
    exit 1
fi

# Check that start-line is positive.
if [ "$START" -lt 0 ]; then
    echo -e "$ERROR Start line is less than 0."
    exit 1
fi

# Check that end-line is positive.
if [ "$END" -lt 0 ]; then
    echo -e "$ERROR End line is less than 0."
    exit 1
fi

NUMOFLINES=$(wc -l < "$FILENAME")

# Check that end-line is not greater than the number of lines in the file.
if [ "$END" -gt "$NUMOFLINES" ]; then
    echo -e "$ERROR End line is greater than number of lines in file."
    exit 1
fi

# The distance from the end of the file to end-line
ENDDIFF=$(( NUMOFLINES - END ))

# For larger files, this will run more quickly. If the distance from the
# end of the file to the end-line is less than the distance from the
# start of the file to the start-line, then start pinching from the
# bottom as opposed to the top.
if [ "$START" -lt "$ENDDIFF" ]; then
    < "$FILENAME" head -n $END | tail -n +$START
else
    < "$FILENAME" tail -n +$START | head -n $(( END-START+1 ))
fi

# Success
exit 0

This might work for you (GNU sed):

sed -ne '16224,16482w newfile' -e '16482q' file

or taking advantage of bash:

sed -n $'16224,16482w newfile\n16482q' file

This might work for you (GNU sed):

sed -ne '16224,16482w newfile' -e '16482q' file

or taking advantage of bash:

sed -n $'16224,16482w newfile\n16482q' file

Just benchmarking 3 solutions given above, that works to me:

  • awk
  • sed
  • "head+tail"

Credits on the 3 solutions goes to:

  • @boxxar
  • @avandeursen
  • @wds
  • @manveru
  • @sibaz
  • @SOFe
  • @fedorqui 'SO stop harming'
  • @Robin A. Meade

I'm using a huge file I find in my server:

# wc fo2debug.1.log
   10421186    19448208 38795491134 fo2debug.1.log

38 Gb in 10.4 million lines.

And yes, I have a logrotate problem. : ))


Make your bets!


Getting 256 lines from the beginning of the file.

# time sed -n '1001,1256p;1256q' fo2debug.1.log | wc -l
256

real    0m0,003s
user    0m0,000s
sys     0m0,004s

# time head -1256 fo2debug.1.log | tail -n +1001 | wc -l
256

real    0m0,003s
user    0m0,006s
sys     0m0,000s

# time awk 'NR==1001, NR==1256; NR==1256 {exit}' fo2debug.1.log | wc -l
256

real    0m0,002s
user    0m0,004s
sys     0m0,000s

Awk won. Technical tie in second place between sed and "head+tail".


Getting 256 lines at the end of the first third of the file.

# time sed -n '3473001,3473256p;3473256q' fo2debug.1.log | wc -l
256

real    0m0,265s
user    0m0,242s
sys     0m0,024s

# time head -3473256 fo2debug.1.log | tail -n +3473001 | wc -l
256

real    0m0,308s
user    0m0,313s
sys     0m0,145s

# time awk 'NR==3473001, NR==3473256; NR==3473256 {exit}' fo2debug.1.log | wc -l
256

real    0m0,393s
user    0m0,326s
sys     0m0,068s

Sed won. Followed by "head+tail" and, finally, awk.


Getting 256 lines at the end of the second third of the file.

# time sed -n '6947001,6947256p;6947256q' fo2debug.1.log | wc -l
A256

real    0m0,525s
user    0m0,462s
sys     0m0,064s

# time head -6947256 fo2debug.1.log | tail -n +6947001 | wc -l
256

real    0m0,615s
user    0m0,488s
sys     0m0,423s

# time awk 'NR==6947001, NR==6947256; NR==6947256 {exit}' fo2debug.1.log | wc -l
256

real    0m0,779s
user    0m0,650s
sys     0m0,130s

Same results.

Sed won. Followed by "head+tail" and, finally, awk.


Getting 256 lines near the end of the file.

# time sed -n '10420001,10420256p;10420256q' fo2debug.1.log | wc -l
256

real    1m50,017s
user    0m12,735s
sys     0m22,926s

# time head -10420256 fo2debug.1.log | tail -n +10420001 | wc -l
256

real    1m48,269s
user    0m42,404s
sys     0m51,015s

# time awk 'NR==10420001, NR==10420256; NR==10420256 {exit}' fo2debug.1.log | wc -l
256

real    1m49,106s
user    0m12,322s
sys     0m18,576s

And suddenly, a twist!

"Head+tail" won. Followed by awk and, finally, sed.


(some hours later...)

Sorry guys!

My analysis above ends up being an example of a basic flaw in doing an analysis.

The flaw is not knowing in depth the resources used for the analysis.

In this case, I used a log file to analyze the performance of a search for a certain number of lines within it.

Using 3 different techniques, searches were made at different points in the file, comparing the performance of the techniques at each point and checking whether the results varied depending on the point in the file where the search was made.

My mistake was to assume that there was a certain homogeneity of content in the log file.

The reality is that long lines appear more frequently at the end of the file.

Thus, the apparent conclusion that longer searches (closer to the end of the file) are better with a given technique, may be biased. In fact, this technique may be better when dealing with longer lines. What remains to be confirmed.


Just benchmarking 3 solutions given above, that works to me:

  • awk
  • sed
  • "head+tail"

Credits on the 3 solutions goes to:

  • @boxxar
  • @avandeursen
  • @wds
  • @manveru
  • @sibaz
  • @SOFe
  • @fedorqui 'SO stop harming'
  • @Robin A. Meade

I'm using a huge file I find in my server:

# wc fo2debug.1.log
   10421186    19448208 38795491134 fo2debug.1.log

38 Gb in 10.4 million lines.

And yes, I have a logrotate problem. : ))


Make your bets!


Getting 256 lines from the beginning of the file.

# time sed -n '1001,1256p;1256q' fo2debug.1.log | wc -l
256

real    0m0,003s
user    0m0,000s
sys     0m0,004s

# time head -1256 fo2debug.1.log | tail -n +1001 | wc -l
256

real    0m0,003s
user    0m0,006s
sys     0m0,000s

# time awk 'NR==1001, NR==1256; NR==1256 {exit}' fo2debug.1.log | wc -l
256

real    0m0,002s
user    0m0,004s
sys     0m0,000s

Awk won. Technical tie in second place between sed and "head+tail".


Getting 256 lines at the end of the first third of the file.

# time sed -n '3473001,3473256p;3473256q' fo2debug.1.log | wc -l
256

real    0m0,265s
user    0m0,242s
sys     0m0,024s

# time head -3473256 fo2debug.1.log | tail -n +3473001 | wc -l
256

real    0m0,308s
user    0m0,313s
sys     0m0,145s

# time awk 'NR==3473001, NR==3473256; NR==3473256 {exit}' fo2debug.1.log | wc -l
256

real    0m0,393s
user    0m0,326s
sys     0m0,068s

Sed won. Followed by "head+tail" and, finally, awk.


Getting 256 lines at the end of the second third of the file.

# time sed -n '6947001,6947256p;6947256q' fo2debug.1.log | wc -l
A256

real    0m0,525s
user    0m0,462s
sys     0m0,064s

# time head -6947256 fo2debug.1.log | tail -n +6947001 | wc -l
256

real    0m0,615s
user    0m0,488s
sys     0m0,423s

# time awk 'NR==6947001, NR==6947256; NR==6947256 {exit}' fo2debug.1.log | wc -l
256

real    0m0,779s
user    0m0,650s
sys     0m0,130s

Same results.

Sed won. Followed by "head+tail" and, finally, awk.


Getting 256 lines near the end of the file.

# time sed -n '10420001,10420256p;10420256q' fo2debug.1.log | wc -l
256

real    1m50,017s
user    0m12,735s
sys     0m22,926s

# time head -10420256 fo2debug.1.log | tail -n +10420001 | wc -l
256

real    1m48,269s
user    0m42,404s
sys     0m51,015s

# time awk 'NR==10420001, NR==10420256; NR==10420256 {exit}' fo2debug.1.log | wc -l
256

real    1m49,106s
user    0m12,322s
sys     0m18,576s

And suddenly, a twist!

"Head+tail" won. Followed by awk and, finally, sed.


(some hours later...)

Sorry guys!

My analysis above ends up being an example of a basic flaw in doing an analysis.

The flaw is not knowing in depth the resources used for the analysis.

In this case, I used a log file to analyze the performance of a search for a certain number of lines within it.

Using 3 different techniques, searches were made at different points in the file, comparing the performance of the techniques at each point and checking whether the results varied depending on the point in the file where the search was made.

My mistake was to assume that there was a certain homogeneity of content in the log file.

The reality is that long lines appear more frequently at the end of the file.

Thus, the apparent conclusion that longer searches (closer to the end of the file) are better with a given technique, may be biased. In fact, this technique may be better when dealing with longer lines. What remains to be confirmed.


The -n in the accept answers work. Here's another way in case you're inclined.

cat $filename | sed "${linenum}p;d";

This does the following:

  1. pipe in the contents of a file (or feed in the text however you want).
  2. sed selects the given line, prints it
  3. d is required to delete lines, otherwise sed will assume all lines will eventually be printed. i.e., without the d, you will get all lines printed by the selected line printed twice because you have the ${linenum}p part asking for it to be printed. I'm pretty sure the -n is basically doing the same thing as the d here.

The -n in the accept answers work. Here's another way in case you're inclined.

cat $filename | sed "${linenum}p;d";

This does the following:

  1. pipe in the contents of a file (or feed in the text however you want).
  2. sed selects the given line, prints it
  3. d is required to delete lines, otherwise sed will assume all lines will eventually be printed. i.e., without the d, you will get all lines printed by the selected line printed twice because you have the ${linenum}p part asking for it to be printed. I'm pretty sure the -n is basically doing the same thing as the d here.

I was looking for an answer to this but I had to end up writing my own code which worked. None of the answers above were satisfactory. Consider you have very large file and have certain line numbers that you want to print out but the numbers are not in order. You can do the following:

My relatively large file for letter in {a..k} ; do echo $letter; done | cat -n > myfile.txt

 1  a
 2  b
 3  c
 4  d
 5  e
 6  f
 7  g
 8  h
 9  i
10  j
11  k

Specific line numbers I want: shuf -i 1-11 -n 4 > line_numbers_I_want.txt

 10
 11
 4
 9

To print these line numbers, do the following. awk '{system("head myfile.txt -n " $0 " | tail -n 1")}' line_numbers_I_want.txt

What the above does is to head the n line then take the last line using tail

If you want your line numbers in order, sort ( is -n numeric sort) first then get the lines.

cat line_numbers_I_want.txt | sort -n | awk '{system("head myfile.txt -n " $0 " | tail -n 1")}'

 4  d
 9  i
10  j
11  k

I was looking for an answer to this but I had to end up writing my own code which worked. None of the answers above were satisfactory. Consider you have very large file and have certain line numbers that you want to print out but the numbers are not in order. You can do the following:

My relatively large file for letter in {a..k} ; do echo $letter; done | cat -n > myfile.txt

 1  a
 2  b
 3  c
 4  d
 5  e
 6  f
 7  g
 8  h
 9  i
10  j
11  k

Specific line numbers I want: shuf -i 1-11 -n 4 > line_numbers_I_want.txt

 10
 11
 4
 9

To print these line numbers, do the following. awk '{system("head myfile.txt -n " $0 " | tail -n 1")}' line_numbers_I_want.txt

What the above does is to head the n line then take the last line using tail

If you want your line numbers in order, sort ( is -n numeric sort) first then get the lines.

cat line_numbers_I_want.txt | sort -n | awk '{system("head myfile.txt -n " $0 " | tail -n 1")}'

 4  d
 9  i
10  j
11  k

Since we are talking about extracting lines of text from a text file, I will give an special case where you want to extract all lines that match a certain pattern.

myfile content:
=====================
line1 not needed
line2 also discarded
[Data]
first data line
second data line
=====================
sed -n '/Data/,$p' myfile

Will print the [Data] line and the remaining. If you want the text from line1 to the pattern, you type: sed -n '1,/Data/p' myfile. Furthermore, if you know two pattern (better be unique in your text), both the beginning and end line of the range can be specified with matches.

sed -n '/BEGIN_MARK/,/END_MARK/p' myfile

Since we are talking about extracting lines of text from a text file, I will give an special case where you want to extract all lines that match a certain pattern.

myfile content:
=====================
line1 not needed
line2 also discarded
[Data]
first data line
second data line
=====================
sed -n '/Data/,$p' myfile

Will print the [Data] line and the remaining. If you want the text from line1 to the pattern, you type: sed -n '1,/Data/p' myfile. Furthermore, if you know two pattern (better be unique in your text), both the beginning and end line of the range can be specified with matches.

sed -n '/BEGIN_MARK/,/END_MARK/p' myfile

The -n in the accept answers work. Here's another way in case you're inclined.

cat $filename | sed "${linenum}p;d";

This does the following:

  1. pipe in the contents of a file (or feed in the text however you want).
  2. sed selects the given line, prints it
  3. d is required to delete lines, otherwise sed will assume all lines will eventually be printed. i.e., without the d, you will get all lines printed by the selected line printed twice because you have the ${linenum}p part asking for it to be printed. I'm pretty sure the -n is basically doing the same thing as the d here.

The -n in the accept answers work. Here's another way in case you're inclined.

cat $filename | sed "${linenum}p;d";

This does the following:

  1. pipe in the contents of a file (or feed in the text however you want).
  2. sed selects the given line, prints it
  3. d is required to delete lines, otherwise sed will assume all lines will eventually be printed. i.e., without the d, you will get all lines printed by the selected line printed twice because you have the ${linenum}p part asking for it to be printed. I'm pretty sure the -n is basically doing the same thing as the d here.

I was looking for an answer to this but I had to end up writing my own code which worked. None of the answers above were satisfactory. Consider you have very large file and have certain line numbers that you want to print out but the numbers are not in order. You can do the following:

My relatively large file for letter in {a..k} ; do echo $letter; done | cat -n > myfile.txt

 1  a
 2  b
 3  c
 4  d
 5  e
 6  f
 7  g
 8  h
 9  i
10  j
11  k

Specific line numbers I want: shuf -i 1-11 -n 4 > line_numbers_I_want.txt

 10
 11
 4
 9

To print these line numbers, do the following. awk '{system("head myfile.txt -n " $0 " | tail -n 1")}' line_numbers_I_want.txt

What the above does is to head the n line then take the last line using tail

If you want your line numbers in order, sort ( is -n numeric sort) first then get the lines.

cat line_numbers_I_want.txt | sort -n | awk '{system("head myfile.txt -n " $0 " | tail -n 1")}'

 4  d
 9  i
10  j
11  k

I was looking for an answer to this but I had to end up writing my own code which worked. None of the answers above were satisfactory. Consider you have very large file and have certain line numbers that you want to print out but the numbers are not in order. You can do the following:

My relatively large file for letter in {a..k} ; do echo $letter; done | cat -n > myfile.txt

 1  a
 2  b
 3  c
 4  d
 5  e
 6  f
 7  g
 8  h
 9  i
10  j
11  k

Specific line numbers I want: shuf -i 1-11 -n 4 > line_numbers_I_want.txt

 10
 11
 4
 9

To print these line numbers, do the following. awk '{system("head myfile.txt -n " $0 " | tail -n 1")}' line_numbers_I_want.txt

What the above does is to head the n line then take the last line using tail

If you want your line numbers in order, sort ( is -n numeric sort) first then get the lines.

cat line_numbers_I_want.txt | sort -n | awk '{system("head myfile.txt -n " $0 " | tail -n 1")}'

 4  d
 9  i
10  j
11  k

Since we are talking about extracting lines of text from a text file, I will give an special case where you want to extract all lines that match a certain pattern.

myfile content:
=====================
line1 not needed
line2 also discarded
[Data]
first data line
second data line
=====================
sed -n '/Data/,$p' myfile

Will print the [Data] line and the remaining. If you want the text from line1 to the pattern, you type: sed -n '1,/Data/p' myfile. Furthermore, if you know two pattern (better be unique in your text), both the beginning and end line of the range can be specified with matches.

sed -n '/BEGIN_MARK/,/END_MARK/p' myfile

Since we are talking about extracting lines of text from a text file, I will give an special case where you want to extract all lines that match a certain pattern.

myfile content:
=====================
line1 not needed
line2 also discarded
[Data]
first data line
second data line
=====================
sed -n '/Data/,$p' myfile

Will print the [Data] line and the remaining. If you want the text from line1 to the pattern, you type: sed -n '1,/Data/p' myfile. Furthermore, if you know two pattern (better be unique in your text), both the beginning and end line of the range can be specified with matches.

sed -n '/BEGIN_MARK/,/END_MARK/p' myfile

Questions with unix tag:

Docker CE on RHEL - Requires: container-selinux >= 2.9 What does `set -x` do? How to find files modified in last x minutes (find -mmin does not work as expected) sudo: npm: command not found How to sort a file in-place How to read a .properties file which contains keys that have a period character using Shell script gpg decryption fails with no secret key error Loop through a comma-separated shell variable Best way to find os name and version in Unix/Linux platform Resource u'tokenizers/punkt/english.pickle' not found Unix command to check the filesize How can I get the IP address from NIC in Python? OSError - Errno 13 Permission denied nginx error connect to php5-fpm.sock failed (13: Permission denied) How to get key names from JSON using jq How/When does Execute Shell mark a build as failure in Jenkins? mkdir's "-p" option How to cat <<EOF >> a file containing code? ssh-copy-id no identities found error Setting PATH environment variable in OSX permanently cut or awk command to print first field of first row How do I pause my shell script for a second before continuing? how to set mongod --dbpath SCP Permission denied (publickey). on EC2 only when using -r flag on directories Command to change the default home directory of a user How to split CSV files as per number of rows specified? Assigning the output of a command to a variable Trim leading and trailing spaces from a string in awk Boolean operators ( &&, -a, ||, -o ) in Bash Send password when using scp to copy files from one server to another centos: Another MySQL daemon already running with the same unix socket /usr/lib/x86_64-linux-gnu/libstdc++.so.6: version CXXABI_1.3.8' not found What does 'stale file handle' in Linux mean? How to run mysql command on bash? How can I use a Python script in the command line without cd-ing to its directory? Is it the PYTHONPATH? Why does ENOENT mean "No such file or directory"? How do I escape spaces in path for scp copy in Linux? Display exact matches only with grep Configure cron job to run every 15 minutes on Jenkins grep without showing path/file:line Bash command line and input limit Get specific line from text file using just shell script How to run SQL in shell script How to use variables in a command in sed? CURL to pass SSL certifcate and password Running Groovy script from the command line Only mkdir if it does not exist Difference between using "chmod a+x" and "chmod 755" Run ssh and immediately execute command How to check the first character in a string in Bash or UNIX shell?

Questions with command-line tag:

Git is not working after macOS Update (xcrun: error: invalid active developer path (/Library/Developer/CommandLineTools) Flutter command not found Angular - ng: command not found how to run python files in windows command prompt? How to run .NET Core console app from the command line Copy Paste in Bash on Ubuntu on Windows How to find which version of TensorFlow is installed in my system? How to install JQ on Mac by command-line? Python not working in the command line of git bash Run function in script from command line (Node JS) How can I pass variable to ansible playbook in the command line? Postgres "psql not recognized as an internal or external command" How to call VS Code Editor from terminal / command line 7-Zip command to create and extract a password-protected ZIP file on Windows? List file using ls command in Linux with full path Find Process Name by its Process ID How to resolve "gpg: command not found" error during RVM installation? How to run .sh on Windows Command Prompt? maven command line how to point to a specific settings.xml for a single command? Run Executable from Powershell script with parameters Running CMD command in PowerShell Command Prompt Error 'C:\Program' is not recognized as an internal or external command, operable program or batch file Build Android Studio app via command line 'ssh' is not recognized as an internal or external command Input from the keyboard in command line application How to force 'cp' to overwrite directory instead of creating another one inside? Use Robocopy to copy only changed files? Change mysql user password using command line mkdir's "-p" option Shell Script: How to write a string to file and to stdout on console? Enter export password to generate a P12 certificate Launch Pycharm from command line (terminal) Difference between IISRESET and IIS Stop-Start command How can I find out if I have Xcode commandline tools installed? Increment variable value by 1 ( shell programming) phpmyadmin #1045 Cannot log in to the MySQL server. after installing mysql command line client Number of processors/cores in command line How to merge 2 JSON objects from 2 files using jq? Displaying output of a remote command with Ansible How do I restart nginx only after the configuration test was successful on Ubuntu? How can I get the current date and time in the terminal and set a custom command in the terminal for it? Run a JAR file from the command line and specify classpath Run R script from command line How to zip a file using cmd line? How to switch between python 2.7 to python 3 from command line? One command to create a directory and file inside it linux command How to find the mysql data directory from command line in windows Execute a command in command prompt using excel VBA how to change directory using Windows command line How do I import an SQL file using the command line in MySQL?

Questions with sed tag:

Retrieve last 100 lines logs How to replace multiple patterns at once with sed? Insert multiple lines into a file after specified pattern using shell script Linux bash script to extract IP address Ansible playbook shell output remove white space from the end of line in linux bash, extract string before a colon invalid command code ., despite escaping periods, using sed RE error: illegal byte sequence on Mac OS X How to use variables in a command in sed? How to cut a string after a specific character in unix Using sed to split a string with a delimiter How to select lines between two marker patterns which may occur multiple times with awk/sed Printing with sed or awk a line following a matching pattern sed: print only matching group Extract XML Value in bash script How to insert strings containing slashes with sed? Convert line endings How to use sed to extract substring Delete empty lines using sed Add text at the end of each line Find and Replace string in all files recursive using grep and sed Why does sed not replace all occurrences? Turning multiple lines into one comma separated line Insert line after first match using sed delete a column with awk or sed How to replace space with comma using sed? how to remove the first two columns in a file using shell (awk, sed, whatever) How to use sed to remove the last n lines of a file How to use sed/grep to extract text between two words? Append file contents to the bottom of existing file in Bash sed with literal string--not input file sed edit file in place Using sed, Insert a line above or below the pattern? How to extract text from a string using sed? How can I strip first X characters from string using sed? Replace whole line containing a string using Sed How to replace an entire line in a text file by line number Replace comma with newline in sed on MacOS? removing new line character from incoming stream using sed Find the line number where a specific word appears with "grep" Change multiple files How to remove all white spaces from a given text file Shell script - remove first and last quote (") from a variable How to merge every two lines into one from the command line? How to add to the end of lines containing a pattern with sed or awk? How to insert a text at the beginning of a file? sed fails with "unknown option to `s'" error Using SED with wildcard How to replace a whole line with sed?

Questions with text-processing tag:

Using multiple delimiters in awk Select random lines from a file How to add a new line of text to an existing file in Java? Add a prefix string to beginning of each line Remove empty lines in a text file via grep How to convert all text to lowercase in Vim How to replace ${} placeholders in a text file? How to use sed to replace only the first occurrence in a file? How can I extract a predetermined range of lines from a text file on Unix?