awk '{$0 = $2 < 104 ? NR : RS}1' inputfile |
sed -Ee '
$aq
/./,/^$/!d;/./H;$ba;/^$/ba;d;:a
g;s/.//;s/\n.*\n|\n/,/;x;s/.*//;x
s/(.*),(.*)/&w file_\1_\2.tmp/
/,/!s/.*/&w file_&.tmp/
' | ed -s inputfile -
Here we use the awk/sed/ed
tools. Awk
first generates line numbers for
all thos lines that are less than 104. For others, it prints an empty line.
Then Sed
comes in and looks at line ranges from non-empty line to the next empty line. And stores up the line numbers in the hold. Now two types of ranges can be found: n,m or plain n. Using these we build up an ed
command set which shall transform such ranges to: n,mw file_n_m.tmp and file_n.tmp respectively. Then ed promptly works on the input file using this dynamically generated ed script to get the lines into their .tmp files.
Here's one way to accomplish your task with Perl
:
perl -lane '
BEGIN { $fmt = sprintf q[%s%%s\n%s], (chr 39)x2; }
if ( $F[1] < 104 ) {
push @A, "@F[0,1]";
if ( eof ) {
my $f = join $", q<printf>, $fmt, map(qq[\"$_\"], @A), q[>], (( ! defined $a ) ? qq[file_${.}.tmp] : qq[file_${a}_${.}.tmp]);
system("$f");
} else { $a //= $.; }
} else {
next if ! defined $a;
$b //= $.-1;
my $f = join $", q<printf>, $fmt, map(qq[\"$_\"], @A), q[>], (( $a == $b ) ? qq[file_$b.tmp] : qq[file_${a}_$b.tmp]);
system("$f");
($a, $b, @A) = (undef)x2;
}
' yourfile
Results:
Given the input , the following 3 files are created: file_1_5.tmp file_7_8.tmp file_10.tmp
with the contents
% more file_1_5.tmp file_7_8.tmp file_10.tmp
::::::::::::::
file_1_5.tmp
::::::::::::::
1 102.0184
2 100.2430
3 103.9029
4 102.7495
5 102.8825
::::::::::::::
file_7_8.tmp
::::::::::::::
7 103.0479
8 101.2433
::::::::::::::
file_10.tmp
::::::::::::::
10 101.5879
Explanation:
First the basic top-level idea: We keep an eye on wheter the 2nd field is falling behind the numeric 104. In the scenario when it does, means we need to print the previous range. Just keep in mind that for unilength ranges, the filename is modified accordingly to reflect that.
The other case when we are in the process of accumulating the current range, ($F[1] < 104) then just keep in mind that while doing so if we hit eof
then we need to print the range now.
P.S.: The system
command is dynamically created by using a dynamically created format, it's data is the first and second fields, and finally the .tmp filename is created according to the range.
$a
and $b
are range begin/end line numbers. Their states will inform us to take the proper decisions.
file_1-10.tmp
? Or several files?