Differences between revisions 145 and 161 (spanning 16 versions)
Revision 145 as of 2009-01-17 16:56:51
Size: 292
Editor: 84
Comment: -9
Revision 161 as of 2022-04-19 05:47:14
Size: 1996
Editor: emanuele6
Comment: replace wc(1) with awk(1) in examples since POSIX wc may print blanks before and after the number (it does in MacOS and FreeBSD/NetBSD); wc(1) is generally not script friendly (see V1_chap05)
Deletions are marked like this. Additions are marked like this.
Line 1: Line 1:
Hi there My younger son who is now working in Germany just sent me your website and it was fascinating reading about your life since then eating missing everyone so much http://carringtonhf.servik.com/restaurant04e.html fresh car, http://basedlm.5nxs.com/restaurant973.html poultry, Great. <<Anchor(faq19)>>
== How can I split a file into line ranges, e.g. lines 1-10, 11-20, 21-30? ==
POSIX specifies the {{{split}}} utility, which can be used for this purpose:

{{{#!highlight bash
split -l 10 input.txt
}}}

For more flexibility you can use {{{sed}}}. The {{{sed}}} command can print e.g. the line number range 1-10:
{{{#!highlight bash
sed 10q # Print lines 1-10 and then quit.
sed '1,5d; 10q' # Print just lines 6-10 by filtering the first 5 then quitting after 10.
}}}

The `d` command stops {{{sed}}} from printing each line. This could alternatively have been done by passing sed the `-n` option and printing lines with the `p` command rather than deleting them with `d`. It makes no difference.

We can now use this to print an arbitrary range of a file (specified by line number):

{{{#!highlight bash
# POSIX shell
file=/etc/passwd
range=10
cur=1
last=$(awk 'END { print NR }' < "$file") # count number of lines
chunk=1
while [ "$cur" -lt "$last" ]
do
    endofchunk=$((cur + range - 1))
    sed -n -e "$cur,${endofchunk}p" -e "${endofchunk}q" "$file" > c"hunk.$(printf %04d "$chunk")"
    chunk=$((chunk + 1))
    cur=$((cur + range))
done
}}}

The previous example uses POSIX [[ArithmeticExpression|arithmetic]], which older [[BourneShell|Bourne shells]] do not have. In that case the following example should be used instead:

{{{#!highlight bash
# legacy Bourne shell; assume no printf either
file=/etc/passwd
range=10
cur=1
last=`awk 'END { print NR }' < file` # count number of lines
chunk=1
while test "$cur" -lt "$last"
do
    endofchunk=`expr $cur + $range - 1`
    sed -n -e "$cur,${endofchunk}p" -e "${endofchunk}q" "$file" > "chunk.$chunk"
    chunk=`expr "$chunk" + 1`
    cur=`expr "$cur" + "$range"`
done
}}}

Awk can also be used to produce a more or less equivalent result:

{{{#!highlight bash
awk -v range=10 '{print > FILENAME "." (int((NR -1)/ range)+1)}' file
}}}

----
CategoryShell

How can I split a file into line ranges, e.g. lines 1-10, 11-20, 21-30?

POSIX specifies the split utility, which can be used for this purpose:

Toggle line numbers
   1 split -l 10 input.txt

For more flexibility you can use sed. The sed command can print e.g. the line number range 1-10:

Toggle line numbers
   1 sed 10q         # Print lines 1-10 and then quit.
   2 sed '1,5d; 10q' # Print just lines 6-10 by filtering the first 5 then quitting after 10.

The d command stops sed from printing each line. This could alternatively have been done by passing sed the -n option and printing lines with the p command rather than deleting them with d. It makes no difference.

We can now use this to print an arbitrary range of a file (specified by line number):

Toggle line numbers
   1 # POSIX shell
   2 file=/etc/passwd
   3 range=10
   4 cur=1
   5 last=$(awk 'END { print NR }' < "$file") # count number of lines
   6 chunk=1
   7 while [ "$cur" -lt "$last" ]
   8 do
   9     endofchunk=$((cur + range - 1))
  10     sed -n -e "$cur,${endofchunk}p" -e "${endofchunk}q" "$file" > c"hunk.$(printf %04d "$chunk")"
  11     chunk=$((chunk + 1))
  12     cur=$((cur + range))
  13 done

The previous example uses POSIX arithmetic, which older Bourne shells do not have. In that case the following example should be used instead:

Toggle line numbers
   1 # legacy Bourne shell; assume no printf either
   2 file=/etc/passwd
   3 range=10
   4 cur=1
   5 last=`awk 'END { print NR }' < file` # count number of lines
   6 chunk=1
   7 while test "$cur" -lt "$last"
   8 do
   9     endofchunk=`expr $cur + $range - 1`
  10     sed -n -e "$cur,${endofchunk}p" -e "${endofchunk}q" "$file" > "chunk.$chunk"
  11     chunk=`expr "$chunk" + 1`
  12     cur=`expr "$cur" + "$range"`
  13 done

Awk can also be used to produce a more or less equivalent result:

Toggle line numbers
   1 awk -v range=10 '{print > FILENAME "." (int((NR -1)/ range)+1)}' file


CategoryShell

BashFAQ/019 (last edited 2022-04-19 12:13:19 by emanuele6)