Skip to main content
added 374 characters in body
Source Link
Kira
  • 4.9k
  • 3
  • 22
  • 35

The first line aggregates the text block, line by line, and also tries to find a number to use as a sorting critea afterwards. The if-clause if($0+0==$0) evals toevaluates true when it finds a number.

The second block executes when it finds an "END" in the input, so it saves the block in an associative array, indexing it using the number found in the block.

awk '{block=block"\n"$0; if($0+0==$0) num=$0;} 
/^END$/ {blks[num]=block; block=""} 
END {for(key in blks) print blks[key]}' file

The last line is just printing every entry of the array when it reaches the end of the input file. Note that the associative array is already sorted (that is how it works internally), so we just need to iterate over it printing every entry.

For instance, look at the following awk script:

echo | awk '{a[2]="b"; a[1]="a"; a[3]="c"; for(key in a) print a[key];}'

It outputs:

a
b
c

In my answer I'm printing an extra \n before each block, I suppose this is not a problem. The output for your example is:

BEGIN
hello4
2
world5
END

BEGIN
hello6
4
END

BEGIN
hello2
5
world1
END

If you don't want the extra line, replace the first block of my awk script with:

{if(length(block)=="0")block=$0; else{block=block"\n"$0; if($0+0==$0) num=$0}}

Here is the one-liner version:

awk '{if(length(block)=="0")block=$0; else{block=block"\n"$0; if($0+0==$0) num=$0}} /^END$/ {blks[num]=block; block=""} END {for(key in blks) print blks[key]}' file

The first line aggregates the text block, line by line, and also tries to find a number to use as a sorting critea afterwards. The if-clause if($0+0==$0) evals to true when it finds a number.

The second block executes when it finds an "END" in the input, so it saves the block in an associative array, indexing it using the number found in the block.

awk '{block=block"\n"$0; if($0+0==$0) num=$0;} 
/^END$/ {blks[num]=block; block=""} 
END {for(key in blks) print blks[key]}' file

The last line is just printing every entry of the array when it reaches the end of the input file. Note that the associative array is already sorted (that is how it works internally), so we just need to iterate over it printing every entry.

For instance, look at the following awk script:

echo | awk '{a[2]="b"; a[1]="a"; a[3]="c"; for(key in a) print a[key];}'

It outputs:

a
b
c

In my answer I'm printing an extra \n before each block, I suppose this is not a problem. The output for your example is:

BEGIN
hello4
2
world5
END

BEGIN
hello6
4
END

BEGIN
hello2
5
world1
END

The first line aggregates the text block, line by line, and also tries to find a number to use as a sorting critea afterwards. The if-clause if($0+0==$0) evaluates true when it finds a number.

The second block executes when it finds an "END" in the input, so it saves the block in an associative array, indexing it using the number found in the block.

awk '{block=block"\n"$0; if($0+0==$0) num=$0;} 
/^END$/ {blks[num]=block; block=""} 
END {for(key in blks) print blks[key]}' file

The last line is just printing every entry of the array when it reaches the end of the input file. Note that the associative array is already sorted (that is how it works internally), so we just need to iterate over it printing every entry.

For instance, look at the following awk script:

echo | awk '{a[2]="b"; a[1]="a"; a[3]="c"; for(key in a) print a[key];}'

It outputs:

a
b
c

In my answer I'm printing an extra \n before each block, I suppose this is not a problem. The output for your example is:

BEGIN
hello4
2
world5
END

BEGIN
hello6
4
END

BEGIN
hello2
5
world1
END

If you don't want the extra line, replace the first block of my awk script with:

{if(length(block)=="0")block=$0; else{block=block"\n"$0; if($0+0==$0) num=$0}}

Here is the one-liner version:

awk '{if(length(block)=="0")block=$0; else{block=block"\n"$0; if($0+0==$0) num=$0}} /^END$/ {blks[num]=block; block=""} END {for(key in blks) print blks[key]}' file
Source Link
Kira
  • 4.9k
  • 3
  • 22
  • 35

The first line aggregates the text block, line by line, and also tries to find a number to use as a sorting critea afterwards. The if-clause if($0+0==$0) evals to true when it finds a number.

The second block executes when it finds an "END" in the input, so it saves the block in an associative array, indexing it using the number found in the block.

awk '{block=block"\n"$0; if($0+0==$0) num=$0;} 
/^END$/ {blks[num]=block; block=""} 
END {for(key in blks) print blks[key]}' file

The last line is just printing every entry of the array when it reaches the end of the input file. Note that the associative array is already sorted (that is how it works internally), so we just need to iterate over it printing every entry.

For instance, look at the following awk script:

echo | awk '{a[2]="b"; a[1]="a"; a[3]="c"; for(key in a) print a[key];}'

It outputs:

a
b
c

In my answer I'm printing an extra \n before each block, I suppose this is not a problem. The output for your example is:

BEGIN
hello4
2
world5
END

BEGIN
hello6
4
END

BEGIN
hello2
5
world1
END