Differences between revisions 10 and 26 (spanning 16 versions)
Revision 10 as of 2007-10-17 17:55:35
Size: 942
Editor: GreyCat
Comment: Yes, remove the cut example, especially if people are going to use --gnu-only-long-options in their examples. :-/
Revision 26 as of 2012-02-27 01:42:40
Size: 1978
Editor: ormaaj
Comment: { mapfile -n $n; head -n 1; } <"$file"
Deletions are marked like this. Additions are marked like this.
Line 1: Line 1:
[[Anchor(faq11)]] <<Anchor(faq11)>>
Line 4: Line 4:
Line 7: Line 8:
Line 11: Line 11:
Line 14: Line 15:
Line 18: Line 18:
Line 19: Line 20:
   head -n $n $file | tail -n 1     head -n $n $file | tail -n 1
Line 21: Line 22:
Another approach, using [[AWK]]:
Line 22: Line 24:
Another approach, using ["AWK"]:
Line 26: Line 27:
Line 30: Line 30:
   x=3 y=4;    x=3 y=4
Line 32: Line 32:
   head -n $y "$file" | tail -n $(($y - $x + 1)) # Same    head -n $y "$file" | tail -n $((y - x + 1))   # Same
   head -n $y "$file" | tail -n +$x # If your tail supports it
Line 35: Line 36:
In Bash 4, this can also be done with mapfile builtin. By changing the value of argument for -n, you can get more than one line in the array MAPFILE:

{{{
   mapfile -ts $((n-1)) -n 1 < "$file"
   echo "${MAPFILE[0]}"
}}}

mapfile can also be used similarly to head while avoiding buffering issues in the event input is a pipe:
{{{
   { mapfile -n $n; head -n 1; } <"$file"
}}}

=== Note ===
In most cases, you should sanitize your variable n to be sure, that it's not containing any of non-digits, before feeding it to sed or awk. You can do it with such simple code:

{{{
   # Bash
   n=${n//[!0-9]/}

   # POSIX
   n=$(printf "%s" "$n"|tr -cd '0-9')
}}}
 . One can argue that an `n` value of `Five brown horses with 3 feet and 9 little piggies.` should yield an error rather than silently behave as though it was really `39`. If you want to code safe, quote your expansions and be done with it. --[[Lhunath]]

----
CategoryShell

How can I print the n'th line of a file?

The dirty (but not quick) way would be:

    sed -n ${n}p "$file"

but this reads the whole input file, even if you only wanted the third line.

This one avoids that problem:

    sed -n "$n{p;q;}" "$file"

At line $n the command "p" is run, printing it, with a "q" afterwards: quit the program.

Another way, more obvious to some, is to grab the last line from a listing of the first n lines:

   head -n $n $file | tail -n 1

Another approach, using AWK:

   awk "NR==$n{print;exit}" file

If you want more than one line, it's pretty easy to adapt any of the previous methods:

   x=3 y=4
   sed -n "$x,${y}p;${y}q;" "$file"                # Print lines $x to $y; quit after $y.
   head -n $y "$file" | tail -n $((y - x + 1))     # Same
   head -n $y "$file" | tail -n +$x                # If your tail supports it
   awk "NR>=$x{print} NR==$y{exit}" "$file"        # Same

In Bash 4, this can also be done with mapfile builtin. By changing the value of argument for -n, you can get more than one line in the array MAPFILE:

   mapfile -ts $((n-1)) -n 1 < "$file"
   echo "${MAPFILE[0]}"

mapfile can also be used similarly to head while avoiding buffering issues in the event input is a pipe:

   { mapfile -n $n; head -n 1; } <"$file"

Note

In most cases, you should sanitize your variable n to be sure, that it's not containing any of non-digits, before feeding it to sed or awk. You can do it with such simple code:

   # Bash
   n=${n//[!0-9]/}

   # POSIX
   n=$(printf "%s" "$n"|tr -cd '0-9')
  • One can argue that an n value of Five brown horses with 3 feet and 9 little piggies. should yield an error rather than silently behave as though it was really 39. If you want to code safe, quote your expansions and be done with it. --Lhunath


CategoryShell

BashFAQ/011 (last edited 2020-05-07 08:35:17 by intranet)