Differences between revisions 1 and 162 (spanning 161 versions)
Revision 1 as of 2007-05-02 23:05:11
Size: 1833
Editor: redondos
Comment:
Revision 162 as of 2022-04-19 12:13:19
Size: 1999
Editor: emanuele6
Comment: fix file -> "$file"
Deletions are marked like this. Additions are marked like this.
Line 1: Line 1:
[[Anchor(faq19)]] <<Anchor(faq19)>>
Line 3: Line 3:
Some Unix systems provide the {{{split}}} utility for this purpose: POSIX specifies the {{{split}}} utility, which can be used for this purpose:
Line 5: Line 5:
{{{
    split --lines 10 --numeric-suffixes input.txt output-
{{{#!highlight bash
split -l 10 input.txt
Line 10: Line 10:
{{{
    sed -n '1,10p'
{{{#!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.
Line 14: Line 15:
This stops {{{sed}}} from printing each line ({{{-n}}}). Instead it only processes the lines in the range 1-10 ("1,10"), and prints them ("p"). {{{sed}}} still reads the input until the end, although we are only interested in lines 1 though 10. We can speed this up by making {{{sed}}} terminate immediately after printing line 10:

{{{
    sed -n -e '1,10p' -e '10q'
}}}

Now the command will quit after reading line 10 ("10q"). The {{{-e}}} arguments indicate a script (instead of a file name). The same can be written a little shorter:

{{{
    sed -n '1,10p;10q'
}}}
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.
Line 28: Line 19:
{{{ {{{#!highlight bash
# POSIX shell
Line 31: Line 23:
firstline=1
maxlines=$(wc -l < "$file") # count number of lines
while (($firstline < $maxlines))
cur=1
last=$(awk 'END { print NR }' < "$file") # count number of lines
chunk=1
while [ "$cur" -lt "$last" ]
Line 35: Line 28:
    ((lastline=$firstline+$range+1))
    sed -n -e "$firstline,${lastline}p" -e "${lastline}q" "$file"
    ((firstline=$firstline+$range+1))
    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))
Line 41: Line 35:
This example uses ["BASH"] and KornShell ArithmeticExpressions, which older [wiki:Self:BourneShell Bourne shells] do not have. In that case the following example should be used instead: 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:
Line 43: Line 37:
{{{ {{{#!highlight bash
# legacy Bourne shell; assume no printf either
Line 46: Line 41:
firstline=1
maxlines=`wc -l < "$file"` # count line numbers
while [ $firstline -le $maxlines ]
cur=1
last=`awk 'END { print NR }' < "$file"` # count number of lines
chunk=1

while test "$cur" -lt "$last"
Line 50: Line 46:
    lastline=`expr $firstline + $range + 1`
    sed -n -e "$firstline,${lastline}p" -e "${lastline}q" "$file"
    firstline=`expr $lastline + 1`
    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"`
Line 55: Line 52:

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:

   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:

   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):

   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:

   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:

   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)