...yet another string of awk/sed questions from a RegExp-Challenged luser %-\

Greetings all,

...here is yet another string of awk/sed questions from a RegExp-Challenged luser :eek:

I'm looking to have sed/awk do some clean-up on routing tables and to that end, I would like to do the following:

1.) If a line contains the word "masks" or "subnets" prepend CR/LF to the beginning of the line.
For Example, turn the following:
C 192.168.1.1/32 is directly connected, Loopback0
172.16.0.0/16 is variably subnetted, 21 subnets, 5 masks
D 172.16.0.128/25
[90/13058560] via 172.21.1.1, 5d04h, Tunnel172021
D 172.16.255.2/32 [90/156160] via 172.16.1.2, 5d05h, Vlan10
D 172.16.255.3/32 [90/156672] via 172.16.1.3, 2w3d, Vlan10
C 172.16.255.1/32 is directly connected, Loopback1
D 172.16.254.0/24 [90/28928] via 172.16.1.3, 2w4d, Vlan10
D 172.16.255.4/32 [90/156672] via 172.16.1.3, 1w4d, Vlan10
D 172.16.255.10/32
[90/13184000] via 172.22.1.1, 5d04h, Tunnel172022
D 172.16.255.11/32
[90/13184000] via 172.21.1.1, 5d04h, Tunnel172021
D 172.16.1.48/30 [90/28416] via 172.16.1.3, 5d05h, Vlan10
D 172.16.10.0/24
[90/13058560] via 172.22.1.1, 5d04h, Tunnel172022
C 172.16.1.0/29 is directly connected, Vlan10
D 172.16.3.0/25 [90/28928] via 172.16.1.3, 1w0d, Vlan10
172.19.0.0/16 is variably subnetted, 8 subnets, 4 masks
D 172.19.255.1/32 [90/12953600] via 172.17.0.38, 5d05h, Tunnel1720170001
D 172.19.255.2/32 [90/12956160] via 172.17.1.2, 4d23h, Vlan10
[90/12956160] via 172.17.0.38, 4d23h, Tunnel1720170001

Into this:
C 192.168.1.1/32 is directly connected, Loopback0

 172.16.0.0/16 is variably subnetted, 21 subnets, 5 masks

D 172.16.0.128/25
[90/13058560] via 172.21.1.1, 5d04h, Tunnel172021
D 172.16.255.2/32 [90/156160] via 172.16.1.2, 5d05h, Vlan10
D 172.16.255.3/32 [90/156672] via 172.16.1.3, 2w3d, Vlan10
C 172.16.255.1/32 is directly connected, Loopback1
D 172.16.254.0/24 [90/28928] via 172.16.1.3, 2w4d, Vlan10
D 172.16.255.4/32 [90/156672] via 172.16.1.3, 1w4d, Vlan10
D 172.16.255.10/32
[90/13184000] via 172.22.1.1, 5d04h, Tunnel172022
D 172.16.255.11/32
[90/13184000] via 172.21.1.1, 5d04h, Tunnel172021
D 172.16.1.48/30 [90/28416] via 172.16.1.3, 5d05h, Vlan10
D 172.16.10.0/24
[90/13058560] via 172.22.1.1, 5d04h, Tunnel172022
C 172.16.1.0/29 is directly connected, Vlan10
D 172.16.3.0/25 [90/28928] via 172.16.1.3, 1w0d, Vlan10

 172.19.0.0/16 is variably subnetted, 8 subnets, 4 masks

D 172.19.255.1/32 [90/12953600] via 172.17.0.38, 5d05h, Tunnel1720170001
D 172.19.255.2/32 [90/12956160] via 172.17.1.2, 4d23h, Vlan10
[90/12956160] via 172.17.0.38, 4d23h, Tunnel1720170001

2.) If a line begins with a [CDS] move this character to the end of the line.
Now the routing table snippet above would look like this:
192.168.1.1/32 is directly connected, Loopback0 C

 172.16.0.0/16 is variably subnetted, 21 subnets, 5 masks
   172.16.0.128/25 D

[90/13058560] via 172.21.1.1, 5d04h, Tunnel172021
172.16.255.2/32 [90/156160] via 172.16.1.2, 5d05h, Vlan10 D
172.16.255.3/32 [90/156672] via 172.16.1.3, 2w3d, Vlan10 D
172.16.255.1/32 is directly connected, Loopback1 C
172.16.254.0/24 [90/28928] via 172.16.1.3, 2w4d, Vlan10 D
172.16.255.4/32 [90/156672] via 172.16.1.3, 1w4d, Vlan10 D
172.16.255.10/32 D
[90/13184000] via 172.22.1.1, 5d04h, Tunnel172022
172.16.255.11/32 D
[90/13184000] via 172.21.1.1, 5d04h, Tunnel172021
172.16.1.48/30 [90/28416] via 172.16.1.3, 5d05h, Vlan10 D
172.16.10.0/24 D
[90/13058560] via 172.22.1.1, 5d04h, Tunnel172022
172.16.1.0/29 is directly connected, Vlan10 C
172.16.3.0/25 [90/28928] via 172.16.1.3, 1w0d, Vlan10 D

 172.19.0.0/16 is variably subnetted, 8 subnets, 4 masks
   172.19.255.1/32 [90/12953600] via 172.17.0.38, 5d05h, Tunnel1720170001 D
   172.19.255.2/32 [90/12956160] via 172.17.1.2, 4d23h, Vlan10 D

[90/12956160] via 172.17.0.38, 4d23h, Tunnel1720170001

3.) If a line begins with a "[" append it to the preceding line (i.e. insert a few backspace characters to basically over-write the CR/LF of the preceding line ?).
Now the routing table snippet above would look like this:
192.168.1.1/32 is directly connected, Loopback0 C

 172.16.0.0/16 is variably subnetted, 21 subnets, 5 masks
   172.16.0.128/25 D [90/13058560] via 172.21.1.1, 5d04h, Tunnel172021
   172.16.255.2/32 [90/156160] via 172.16.1.2, 5d05h, Vlan10 D
   172.16.255.3/32 [90/156672] via 172.16.1.3, 2w3d, Vlan10 D
   172.16.255.1/32 is directly connected, Loopback1 C
   172.16.254.0/24 [90/28928] via 172.16.1.3, 2w4d, Vlan10 D
   172.16.255.4/32 [90/156672] via 172.16.1.3, 1w4d, Vlan10 D
   172.16.255.10/32 D [90/13184000] via 172.22.1.1, 5d04h, Tunnel172022
   172.16.255.11/32 D [90/13184000] via 172.21.1.1, 5d04h, Tunnel172021
   172.16.1.48/30 [90/28416] via 172.16.1.3, 5d05h, Vlan10 D
   172.16.10.0/24 D [90/13058560] via 172.22.1.1, 5d04h, Tunnel172022
   172.16.1.0/29 is directly connected, Vlan10 C
   172.16.3.0/25 [90/28928] via 172.16.1.3, 1w0d, Vlan10 D

 172.19.0.0/16 is variably subnetted, 8 subnets, 4 masks
   172.19.255.1/32 [90/12953600] via 172.17.0.38, 5d05h, Tunnel1720170001 D
   172.19.255.2/32 [90/12956160] via 172.17.1.2, 4d23h, Vlan10 D [90/12956160] via 172.17.0.38, 4d23h, Tunnel1720170001

4.) Delete all the leading space (I think this will do the trick: sed 's/^[ ]*//g')
5.) Sort the one or more lines that appear between blank lines, by IP address.
Now the routing table snippet above would look like this:
192.168.1.1/32 is directly connected, Loopback0 C

172.16.0.0/16 is variably subnetted, 21 subnets, 5 masks
172.16.0.128/25 D [90/13058560] via 172.21.1.1, 5d04h, Tunnel172021
172.16.1.0/29 is directly connected, Vlan10 C
172.16.1.48/30 [90/28416] via 172.16.1.3, 5d05h, Vlan10 D
172.16.3.0/25 [90/28928] via 172.16.1.3, 1w0d, Vlan10 D
172.16.10.0/24 D [90/13058560] via 172.22.1.1, 5d04h, Tunnel172022
172.16.254.0/24 [90/28928] via 172.16.1.3, 2w4d, Vlan10 D
172.16.255.1/32 is directly connected, Loopback1 C
172.16.255.2/32 [90/156160] via 172.16.1.2, 5d05h, Vlan10 D
172.16.255.3/32 [90/156672] via 172.16.1.3, 2w3d, Vlan10 D
172.16.255.4/32 [90/156672] via 172.16.1.3, 1w4d, Vlan10 D
172.16.255.10/32 D [90/13184000] via 172.22.1.1, 5d04h, Tunnel172022
172.16.255.11/32 D [90/13184000] via 172.21.1.1, 5d04h, Tunnel172021

172.19.0.0/16 is variably subnetted, 8 subnets, 4 masks
172.19.255.1/32 [90/12953600] via 172.17.0.38, 5d05h, Tunnel1720170001 D
172.19.255.2/32 [90/12956160] via 172.17.1.2, 4d23h, Vlan10 D [90/12956160] via 172.17.0.38, 4d23h, Tunnel1720170001

In the most general terms, I'm struggling to work with metacharacters like tab, CR/LF and backspace (1. and 3. above) and with chunks of a file that contain multiple lines (5.) in sed.

I image awk may be the better choice for this task but I'm completely unfamiliar with awk scripting.

So what do you think? Is the above even possible?
Is it a complete kludge to which you can offer a more elegant and efficient solution?
I'm novice enough in the scripting world so that just about everything I do is a bit of a kludge :confused:

...anyway...PLEASE let me know your thoughts on how I might make a large collection of routing tables easier to read/report on/summarize/further analyze or just how I might do a couple of cool new tricks with sed or awk (...or whatever other tool you think is suited to this task).

THANK YOU VERY MUCH, in advance, for any help or suggestions you may offer me!

--Steve

Please remove all the font and size changes from your post; all they do is make it hard to edit the reply.

Put scripts and command output in [code] tags.

...sorry about that. I certainly didn't mean to post with all kinds of weird formatting. :frowning:

My previous post was just text entered into the forums' Web interface.

...I'll try it again.

--Steve

---------- Post updated at 02:20 PM ---------- Previous update was at 02:06 PM ----------

Greetings all,

...here is yet another string of awk/sed questions from a RegExp-Challenged luser

I'm looking to have sed/awk do some clean-up on routing tables and to that end, I would like to do the following:

1.) If a line contains the word "masks" or "subnets" prepend CR/LF to the beginning of the line.
For Example, turn the following:

 
C 192.168.1.1/32 is directly connected, Loopback0
172.16.0.0/16 is variably subnetted, 21 subnets, 5 masks
D 172.16.0.128/25 
[90/13058560] via 172.21.1.1, 5d04h, Tunnel172021
D 172.16.255.2/32 [90/156160] via 172.16.1.2, 5d05h, Vlan10
D 172.16.255.3/32 [90/156672] via 172.16.1.3, 2w3d, Vlan10
C 172.16.255.1/32 is directly connected, Loopback1
D 172.16.254.0/24 [90/28928] via 172.16.1.3, 2w4d, Vlan10
D 172.16.255.4/32 [90/156672] via 172.16.1.3, 1w4d, Vlan10
D 172.16.255.10/32 
[90/13184000] via 172.22.1.1, 5d04h, Tunnel172022
D 172.16.255.11/32 
[90/13184000] via 172.21.1.1, 5d04h, Tunnel172021
D 172.16.1.48/30 [90/28416] via 172.16.1.3, 5d05h, Vlan10
D 172.16.10.0/24 
[90/13058560] via 172.22.1.1, 5d04h, Tunnel172022
C 172.16.1.0/29 is directly connected, Vlan10
D 172.16.3.0/25 [90/28928] via 172.16.1.3, 1w0d, Vlan10
172.19.0.0/16 is variably subnetted, 8 subnets, 4 masks
D 172.19.255.1/32 [90/12953600] via 172.17.0.38, 5d05h, Tunnel1720170001
D 172.19.255.2/32 [90/12956160] via 172.17.1.2, 4d23h, Vlan10
[90/12956160] via 172.17.0.38, 4d23h, Tunnel1720170001

=======================================================

Into this:

 
C 192.168.1.1/32 is directly connected, Loopback0
 
172.16.0.0/16 is variably subnetted, 21 subnets, 5 masks
D 172.16.0.128/25 
[90/13058560] via 172.21.1.1, 5d04h, Tunnel172021
D 172.16.255.2/32 [90/156160] via 172.16.1.2, 5d05h, Vlan10
D 172.16.255.3/32 [90/156672] via 172.16.1.3, 2w3d, Vlan10
C 172.16.255.1/32 is directly connected, Loopback1
D 172.16.254.0/24 [90/28928] via 172.16.1.3, 2w4d, Vlan10
D 172.16.255.4/32 [90/156672] via 172.16.1.3, 1w4d, Vlan10
D 172.16.255.10/32 
[90/13184000] via 172.22.1.1, 5d04h, Tunnel172022
D 172.16.255.11/32 
[90/13184000] via 172.21.1.1, 5d04h, Tunnel172021
D 172.16.1.48/30 [90/28416] via 172.16.1.3, 5d05h, Vlan10
D 172.16.10.0/24 
[90/13058560] via 172.22.1.1, 5d04h, Tunnel172022
C 172.16.1.0/29 is directly connected, Vlan10
D 172.16.3.0/25 [90/28928] via 172.16.1.3, 1w0d, Vlan10
 
172.19.0.0/16 is variably subnetted, 8 subnets, 4 masks
D 172.19.255.1/32 [90/12953600] via 172.17.0.38, 5d05h, Tunnel1720170001
D 172.19.255.2/32 [90/12956160] via 172.17.1.2, 4d23h, Vlan10
[90/12956160] via 172.17.0.38, 4d23h, Tunnel1720170001

=======================================================

2.) If a line begins with a [CDS] move this character to the end of the line.
Now the routing table snippet above would look like this:

 
192.168.1.1/32 is directly connected, Loopback0 C
 
172.16.0.0/16 is variably subnetted, 21 subnets, 5 masks
172.16.0.128/25 D
[90/13058560] via 172.21.1.1, 5d04h, Tunnel172021
172.16.255.2/32 [90/156160] via 172.16.1.2, 5d05h, Vlan10 D
172.16.255.3/32 [90/156672] via 172.16.1.3, 2w3d, Vlan10 D
172.16.255.1/32 is directly connected, Loopback1 C
172.16.254.0/24 [90/28928] via 172.16.1.3, 2w4d, Vlan10 D
172.16.255.4/32 [90/156672] via 172.16.1.3, 1w4d, Vlan10 D
172.16.255.10/32 D
[90/13184000] via 172.22.1.1, 5d04h, Tunnel172022
172.16.255.11/32 D
[90/13184000] via 172.21.1.1, 5d04h, Tunnel172021
172.16.1.48/30 [90/28416] via 172.16.1.3, 5d05h, Vlan10 D
172.16.10.0/24 D
[90/13058560] via 172.22.1.1, 5d04h, Tunnel172022
172.16.1.0/29 is directly connected, Vlan10 C
172.16.3.0/25 [90/28928] via 172.16.1.3, 1w0d, Vlan10 D
 
172.19.0.0/16 is variably subnetted, 8 subnets, 4 masks
172.19.255.1/32 [90/12953600] via 172.17.0.38, 5d05h, Tunnel1720170001 D
172.19.255.2/32 [90/12956160] via 172.17.1.2, 4d23h, Vlan10 D
[90/12956160] via 172.17.0.38, 4d23h, Tunnel1720170001

=======================================================

3.) If a line begins with a "[" append it to the preceding line (i.e. insert a few backspace characters to basically over-write the CR/LF of the preceding line ?).
Now the routing table snippet above would look like this:

 
192.168.1.1/32 is directly connected, Loopback0 C
 
172.16.0.0/16 is variably subnetted, 21 subnets, 5 masks
172.16.0.128/25 D [90/13058560] via 172.21.1.1, 5d04h, Tunnel172021
172.16.255.2/32 [90/156160] via 172.16.1.2, 5d05h, Vlan10 D
172.16.255.3/32 [90/156672] via 172.16.1.3, 2w3d, Vlan10 D
172.16.255.1/32 is directly connected, Loopback1 C
172.16.254.0/24 [90/28928] via 172.16.1.3, 2w4d, Vlan10 D
172.16.255.4/32 [90/156672] via 172.16.1.3, 1w4d, Vlan10 D
172.16.255.10/32 D [90/13184000] via 172.22.1.1, 5d04h, Tunnel172022
172.16.255.11/32 D [90/13184000] via 172.21.1.1, 5d04h, Tunnel172021
172.16.1.48/30 [90/28416] via 172.16.1.3, 5d05h, Vlan10 D
172.16.10.0/24 D [90/13058560] via 172.22.1.1, 5d04h, Tunnel172022
172.16.1.0/29 is directly connected, Vlan10 C
172.16.3.0/25 [90/28928] via 172.16.1.3, 1w0d, Vlan10 D
 
172.19.0.0/16 is variably subnetted, 8 subnets, 4 masks
172.19.255.1/32 [90/12953600] via 172.17.0.38, 5d05h, Tunnel1720170001 D
172.19.255.2/32 [90/12956160] via 172.17.1.2, 4d23h, Vlan10 D [90/12956160] via 172.17.0.38, 4d23h, Tunnel1720170001

=======================================================
4.) Delete all the leading space (I think this will do the trick):

sed 's/^[ ]*//g'

5.) Sort the one or more lines that appear between blank lines, by IP address.
Now the routing table snippet above would look like this:

192.168.1.1/32 is directly connected, Loopback0 C

172.16.0.0/16 is variably subnetted, 21 subnets, 5 masks
172.16.0.128/25 D [90/13058560] via 172.21.1.1, 5d04h, Tunnel172021
172.16.1.0/29 is directly connected, Vlan10 C
172.16.1.48/30 [90/28416] via 172.16.1.3, 5d05h, Vlan10 D
172.16.3.0/25 [90/28928] via 172.16.1.3, 1w0d, Vlan10 D
172.16.10.0/24 D [90/13058560] via 172.22.1.1, 5d04h, Tunnel172022
172.16.254.0/24 [90/28928] via 172.16.1.3, 2w4d, Vlan10 D
172.16.255.1/32 is directly connected, Loopback1 C
172.16.255.2/32 [90/156160] via 172.16.1.2, 5d05h, Vlan10 D
172.16.255.3/32 [90/156672] via 172.16.1.3, 2w3d, Vlan10 D
172.16.255.4/32 [90/156672] via 172.16.1.3, 1w4d, Vlan10 D
172.16.255.10/32 D [90/13184000] via 172.22.1.1, 5d04h, Tunnel172022
172.16.255.11/32 D [90/13184000] via 172.21.1.1, 5d04h, Tunnel172021

172.19.0.0/16 is variably subnetted, 8 subnets, 4 masks
172.19.255.1/32 [90/12953600] via 172.17.0.38, 5d05h, Tunnel1720170001 D
172.19.255.2/32 [90/12956160] via 172.17.1.2, 4d23h, Vlan10 D [90/12956160] via 172.17.0.38, 4d23h, Tunnel1720170001

In the most general terms, I'm struggling to work with metacharacters like tab, CR/LF and backspace (1. and 3. above) and with chunks of a file that contain multiple lines (5.) in sed.

I image awk may be the better choice for this task but I'm completely unfamiliar with awk scripting.

So what do you think? Is the above even possible?
Is it a complete kludge to which you can offer a more elegant and efficient solution?

I'm novice enough in the scripting world so that just about everything I do is a bit of a kludge

...anyway...PLEASE let me know your thoughts on how I might make a large collection of routing tables easier to read/report on/summarize/further analyze or just how I might do a couple of cool new tricks with sed or awk (...or whatever other tool you think is suited to this task).

THANK YOU VERY MUCH, in advance, for any help or suggestions you may offer me!

--Steve

---------- Post updated at 02:24 PM ---------- Previous update was at 02:20 PM ----------

...is my latest post in a more readable/usable format?

--Steve

---------- Post updated at 02:37 PM ---------- Previous update was at 02:24 PM ----------

...I've made a little progress on this problem since my first post (...but knowing me my "solution" is more klunky than it should be).

...anyway, here's what I've come up with to move the initial route source identifiers to the end of their respective line and than clear all the leading white space from every line:

sed '/^D EX/s/.$/\tD EX/;s/^D EX//;/^D/s/.$/\tD/;s/^D//;/^C/s/.$/\tC/;s/^C//;/^S\*/s/.$/\tS\*/;s/^S\*//;/^S/s/.$/\tS/;s/^S//;s/^[ \t]*//' GNWAN-RT > GNWAN01-RT

I'd like to make this whole line cleaner by handling all the route source identifiers in a single characters set, but I don't yet know how to do this.
The character set would look something like this:

["D EX"D"S*"SC]

Appending a line to the one preceding is still a mystery to me too.

...anyway...thanks for looking at this!

--Steve

awk '/masks/ || /subnet/ { print "" } { print }' "$file"

Nice puzzle, Steve. This works in ksh. Do you have that on your system?

#!/bin/ksh
{ sed '/masks/ s/^/\n/'  infile | sed 's/^\([CDS]\) \(.*\)$/\2 \1/' |\
while read line; do
  case $line in
      \[*) printf "$prevline $line\n"
           prevline="" ;;
      *subnets*|*masks*)
           echo;&
      *)   if [[ $prevline != "" ]]; then
             echo $prevline
           fi
           prevline=$line  ;;
  esac;
done;
if [[ $prevline != "" ]]; then
  echo $prevline
fi } | \
while read firstline; do
  while read line; do
    if [[ $firstline != "" ]]; then
      echo $firstline
      firstline=""
    fi
    if [[ $line != "" ]]; then
      echo $line
    else
      break
    fi
  done|sort -n -t. -k1,1 -k2,2 -k3,3 -k4,4
  echo
done
if [[ $firstline != "" ]]; then
  echo $firstline
fi

The sort statement is very implementation dependent. This syntax is for GNU sort.

If you use [ -n "$var" ] instead of [[ $var != "" ]], the script will work in any shell.

Why two calls to sed?

sed -e '/masks/ s/^/\n/' -e 's/^\([CDS]\) \(.*\)$/\2 \1/' infile

That is POSIX sort which most systems now have; that means your sort code will work almost everywhere.

The Force is < STRONG > with you two !!! :smiley:

<<< THANK YOU SO MUCH >>> for these <<< AMAZING >>> REPLIES !!!

--Steve

Glad you like it Steve!
Thanks for your comments CFA.

...a possibly trivial, follow-up question.

Is it possible to treat several characters as a single option within a character set?

For instance, some of my routing table entries begin with "D EX" or "S*"

Is it possible to somehow include these strings along with the individual characters in the set [DCS] (and obviously match on and move these strings to the end end of their respective line before evaluating the individual characters) or would I need something like a separate invocation of SED to do this?

Thanks!
--Steve

Look at the -e option in my last post in this thread.

(And read the man page.)

...got it.

Thanks CFA.

--Steve

---------- Post updated at 05:48 PM ---------- Previous update was at 05:41 PM ----------

I imagine this is just being caused by a minor typo or something but I'm getting the following error when I run the script:

 
$ ./CleanRouteTable.sh < GNWAN-RT
./CleanRouteTable.sh: line 8: syntax error near unexpected token `&'
./CleanRouteTable.sh: line 8: ` echo; &'

BTW, don't hate me for this, but I'm currently trying to run this using Cygwin :eek:

...so maybe that's also a problem here... :frowning:

--Steve

Did you read the error message?

It's a problem, but that's not relevant in this instance.

The problem is with the ;& body termination, which is used for "falling through" in case statements. I guess this is a Kornshell-only feature.

I have adjusted the code somewhat so that it works in both ksh and bash:

#!/bin/ksh
# First Step 2
mergedline=0
{ sed 's/^\([CDS]\) \(.*\)$/\2 \1/' infile |\
while read line; do
  case $line in
      # Step 3
      \[*) printf "$prevline $line\n"
           mergedline=1
           prevline="" ;;
      # Step 4
      *)   if [[ $mergedline -eq 0 ]]; then
             echo $prevline
      # Step 1
             case $line in
               *subnets*|*masks*) echo ;;
             esac
           fi
           mergedline=0
           prevline=$line  ;;
  esac;
done;
if [[ $mergedline -eq 1 ]]; then
  echo $prevline
fi } | \
while read firstline; do  # Step 5
  while read line; do
    if [[ $firstline != "" ]]; then
      echo $firstline
      firstline=""
    fi
    if [[ $line != "" ]]; then
      echo $line
    else
      break
    fi
  done|sort -n -t. -k1,1 -k2,2 -k3,3 -k4,4
  echo
done
if [[ $firstline != "" ]]; then
  echo $firstline
fi

---------- Post updated at 05:59 PM ---------- Previous update was at 05:36 PM ----------

And this version works in sh/dash too:

#!/bin/sh
# First Step 2
mergedline=0
{ sed 's/^\([CDS]\) \(.*\)$/\2 \1/' infile |\
while read line; do
  case $line in
      # Step 3
      \[*) printf "$prevline $line\n"
           mergedline=1
           prevline="" ;;
      # Step 4
      *)   if [ $mergedline -eq 0 ]; then
             echo $prevline
      # Step 1
             case $line in
               *subnets*|*masks*) echo ;;
             esac
           fi
           mergedline=0
           prevline=$line  ;;
  esac;
done;
if [ $mergedline -eq 1 ]; then
  echo $prevline
fi } | \
while read firstline; do  # Step 5
  while read line; do
    if [ -n "$firstline" ]; then
      echo $firstline
      firstline=""
    fi
    if [ -n "$line" ]; then
      echo $line
    else
      break
    fi
  done|sort -n -t. -k1,1 -k2,2 -k3,3 -k4,4
  echo
done
if [ -n "$firstline" ]; then
  echo $firstline
fi

Hello again, Scrutinizer.

...I'll apologize in advance for having defaced your code; My script-foo is no match for yours so I've dumbed it down a bit. :frowning:

...what can I say...I've got a lot to learn.

...anyway, below is what I've got right now. This runs fairly well but stumbles at at least one point on our live routing tables.

Sometimes there are multiple equal-cost paths to a particular network so what this means in terms of processing the routing table with this script is, there may be several lines in a row which begin with a "[" and need to be joined to the line above them iteratively.

I imagine this means I need something like a WHILE loop for Step 3. to ensure I've joined all the "[" lines before moving on.

How would you suggest I proceed?

 
#!/bin/bash
# First Step 2
mergedline=0
{ sed '/^D EX/s/$/\tD EX/;s/^D EX//; 
         /^D/s/$/\tD/;s/^D//; 
         /^C/s/$/\tC/;s/^C//; 
         /^S\*/s/$/\tS\*/;s/^S\*//; 
         /^S/s/$/\tS/;s/^S//; 
         s/^[ \t]*//; 
         /masks/s/^/\n/; 
         /subnets/s/^/\n/' $1 |\
while read line; do
  case $line in
      # Step 3
      \[*) printf "$prevline $line\n"
           mergedline=1
           prevline="" ;;
      # Step 4
      *)   if [[ $mergedline -eq 0 ]]; then
             echo $prevline
      # Step 1
             case $line in
               *subnets*|*masks*) echo ;;
             esac
           fi
           mergedline=0
           prevline=$line  ;;
  esac;
done;
if [[ $mergedline -eq 1 ]]; then
  echo $prevline
fi } | \
while read firstline; do  # Step 5
  while read line; do
    if [ -n "$firstline" ]; then
      echo $firstline
      firstline=""
    fi
    if [ -n "$line" ]; then
      echo $line
    else
      break
    fi
  done|sort -n -t. -k1,1 -k2,2 -k3,3 -k4,4
  echo
done
if  [ -n "$firstline" ]; then
  echo $firstline
fi

Actually, the code could be simplified and cleaned up a little. Also the first '{' was in the wrong place and should be in front of the while loop. For ksh this does not matter, but is does for other shells..

#!/bin/ksh
# check
if [ -z "$1" ]; then
  echo "Usage: ${0##*/} inputfile"; exit 1
fi

# First Step 2
sed 's/^\([CDS]\) \(.*\)$/\2 \1/' "$1" |\
{ while read line; do
    case $line in
        # Step 3
        \[*) prevline="$prevline $line";;
        # Step 4
        *)   echo $prevline
        # Step 1
             case $line in
               *subnets*|*masks*) echo ;;
             esac
             prevline=$line  ;;
    esac;
  done;
  echo $prevline
} | \
{ while read firstline; do  # Step 5
    while read line; do
      if [ -n "$firstline" ]; then
        echo $firstline
        firstline=""
      fi
      if [ -n "$line" ]; then
        echo $line
      else
        break
      fi
    done|sort -n -t. -k1,1 -k2,2 -k3,3 -k4,4
    echo
  done
  if [ -n "$firstline" ]; then
    echo $firstline
  fi
}

If you replace the sed string with your own, you can either leave out:

;/masks/s/^/\n/; /subnets/s/^/\n/

or remove:

             case $line in
               *subnets*|*masks*) echo ;;
             esac

since one of them is superfluous.

The script should work with bash or posix shell as well.

without the 'sorting' requirement 5:
nawk -f steve.awk myFile

steve.awk:

/(masks|subnets)/ { $0=ORS $0 }
$1 ~ /^[CDS]$/ { $0=$0 OFS $1;$1=""}
{sub("^ *", "");}
/^[[]/{ line = line OFS $0; next}
{if (length(line)) print line; line=$0}
END {print line}

One more addition. It is of course better to use functions instead of the mad pipe spaghetti..:rolleyes:

#!/bin/sh
# check
if [ -z "$1" ]; then
  echo "Usage: ${0##*/} inputfile"; exit 1
fi

process_lines() {
  while read line; do
    case $line in
        \[*) prevline="$prevline $line";;   # Step 3
        *)   echo $prevline                 # Step 4
             case $line in                  # Step 1
               *subnets*|*masks*) echo ;;
             esac
             prevline=$line  ;;
    esac;
  done;
  echo $prevline
}

paragraphsort() {
  while read firstline; do                  # Step 5
    while read line; do
      if [ -n "$firstline" ]; then
        echo $firstline
        firstline=""
      fi
      if [ -n "$line" ]; then
        echo $line
      else
        break
      fi
    done|sort -n -t. -k1,1 -k2,2 -k3,3 -k4,4
    echo
  done
  if [ -n "$firstline" ]; then
    echo $firstline
  fi
}

# Step 2
sed 's/^\([CDS]\) \(.*\)$/\2 \1/' "$1" |process_lines|paragraphsort