Need help separating file lines into three classes

Hi folks,

What I have are config files with lines that: are blank, start with a "!" or start with char's(or a blank space and then char's)

I am using ksh

I can display each line by doing:

for INDEX in {0..$LENGTH}
do
   echo "${data[$INDEX]}" 
done

What I need to do requires I can separate the lines into the three classes
the psudo code looks like this:

for INDEX in {0..$LENGTH}
do
 -psudoCode
  If echo ^{${data[$INDEX]}"} = "  "  # note: two blanks in quotes
    then
      If echo ^{${data[$INDEX]}"} = "!"
        then
          do something
        else
          do something else
     fi
  fi
 -end psudoCode
done

Now, I know I can do this using if and regex, but have tried many ways...and searched the web for answers to try. I can't seem to crack this and am hoping someone can help

Thanks!

Marc

awk is inherently able to deal with this.
please give us sample input and expected output.

What we have so far is interesting but not on the path to helping you.

file starts below
_______________________

!
version 12.4
service timestamps debug datetime msec
service timestamps log datetime msec
no service password-encryption
!
hostname MarcsTestbox
!
boot-start-marker
boot-end-marker
!
logging message-counter syslog
enable secret {FIELD DELETED] [FIELD DELETED]
!
no aaa new-model
clock timezone
.
.
.
__________
End of input

Expected output after first processing will take the first of actual config line after a "!" as a heading and provide a menu.
So from above, the first run through the $data[$INDEX] array would provide:

"Menu of options:

1 version
2 Hostname
3 boot
4 logging"

Then, after capturing the data for a menu, I want to be able to select a number and get the block corresponding to that heading

Ex:
if I hit "2" and enter
I get:

hostname MarcsTestbox

if I hit "4" and enter
I get:

logging message-counter syslog
enable secret {FIELD DELETED] [FIELD DELETED]

Thanks for helping!

Marc

Please repost your sample input using code tags. Since you've used the circumflex character in your pseudocode, I'm assuming that you're looking for some lines starting with two space characters; but none of the lines in your sample input have any leading space characters. :confused:
Please ignore this posting. When I first read message #3 in this thread, I was trying to make sense of it given the pseudocode in message #1. I now realize that message #1 can be ignored and the full specification of what you want is in message #3.

On top,I'd be surprised if your snippet for INDEX in {0..$LENGTH} would work...

!
version 12.4
service timestamps debug datetime msec
service timestamps log datetime msec
no service password-encryption
!
hostname MarcsTestbox
!
boot-start-marker
boot-end-marker
!
logging message-counter syslog
enable secret {FIELD DELETED] [FIELD DELETED]
!
no aaa new-model
clock timezone
  .
  .
  .

Expected output after first processing will take the first of actual config line after a "!" as a heading and provide a menu.
So from above, the first run through the $data[$INDEX] array would provide:

"Menu of options:

 1 version
2 Hostname
3 boot
4 logging"

Then, after capturing the data for a menu, I want to be able to select a number and get the block corresponding to that heading

Ex:
if I hit "2" and enter
I get:

hostname MarcsTestbox

if I hit "4" and enter
I get:

logging message-counter syslog
enable secret {FIELD DELETED] [FIELD DELETED]

Thanks for helping!

Marc

Rudi,
In recent versions of ksh:

x=4
for i in {0..$x}
do echo $i
done

produces:

0
1
2
3
4

Any suggestions on my process?
I can get the array to read out,

I even used a cut to pull the first two characters:

START=`echo $data[$INDEX] | cut -c1-2

But even once I tested that $START was collecting the correct data, I could not get my if statements to work.

Add to that, I know there is a more efficient way, but I don't know that method either.

Marc

I'm working on it. I have a way to do it in awk and I almost have a way to do it entirely in ksh, but I still have some testing to do...

I'm using arrays in a completely different way than you did.

I eventually want to learn awk too.
So if you can explain it, I'd like that

But thanks for your help

Marc

OK. Finally, here it is. The following Korn shell script provides a way to read a data file (named data ), extract data items from that file, create a menu of the data items, and allows the user to interactively request the data associated with each menu entry. It actually provides two sample solutions for this problem and runs both solutions so the user can see the differences in behavior.

The first method is an awk script. It only uses features in awk that are included in the POSIX Standards. (Note that on Solaris systems, you'll need to use nawk or /usr/xpg4/bin/awk rather than /usr/bin/awk.)

The second method is a Korn shell script. It makes use of a few features that are not available in old versions of ksh; you'll need a version newer than November 16, 1988. It also makes use of some features that are not required by the POSIX standards.

The awk and ksh scripts use the same variable names. A summary of the variable names and their uses is provided in comments between the two scripts.

Here it is:

#!/bin/ksh
echo '*** 1st method: Using awk script... ***'
# Note that the variable names used in this awk script use the same variable
# names as the shell variables in the ksh script below.  A list of the
# variables and their use is included below for the ksh script.
#
# Note also that the echo and cat here are critical to allow awk to detect the
# EOF on the data file and display the prompt for the first round of
# interactive user input...
(echo;cat)|awk 'BEGIN{m = "Menu of options:\n"}
function mp(){printf("\n%s", m)}
{       # Throw away leading and trailing  whitespace on all input.
        sub(/^[[:space:]]*/, "")
        sub(/[[:space:]]*$/, "")
}
FNR == NR {
        # We are reading the data file here...
        if($0 == "") next # skip blank lines, sub() above made blank lines empty
        if($0 == "!")
                # Note that next non-empty data line starts a menu entry
                d1=1
        else if(d1) {
                # First line in data for menu choice mc, create menu entry
                d[++mc] = $0 "\n"
                d1=0
                m = sprintf("%s%d %s\n", m, mc,
                        match($0, /[^[:alpha:]]/) > 0 ? \
                                substr($0, 1, RSTART - 1) : $0)
        } else  # Subsequent line in data for menu choice mc
                d[mc] = d[mc] $0 "\n"
        next
}
FNR == 1 {
        # We are reading the line produced by the echo here.  Finish up the
        # menu, print the menu, and wait for the user to enter a selection:
        m = sprintf("%sEnter your choice 1 to %d (ctl-D to exit):\n", m, mc)
        mp()
        next
}
{       if($0 ~ /[^[:digit:]]/ || $0 < 1 || $0 > mc) printf("Invalid choice.\n")
        else printf("%s", d[$0])
        mp()
}' data -

sleep 1
echo '*** 2nd method: Just using ksh... ***'

# Shell variable data dictionary:
# d[x]  "d"ata for menu item x
# d1    != 0 => looking for "d"ata line #"1" for menu entry $mc
# in    current "in"put line
# m     "m"enu
# mc    "m"enu entry "c"ount
d1=0
m='Menu of options:'
while read -r in
do      if [[ "$in" == '' ]]
        then    continue        # skip empty lines in data file
        elif [[ "$in" == '!' ]]
        then    d1=1            # Next non-blank line is where we'll find the
                                # menu text and the start of the data text.
        elif [[ $d1 == 1 ]]
        then    # Gather data from 1st data line for a menu item.
                ((mc++))
                d[mc]="$(printf '%s\n' "$in")" # 1st line of data
                # Add a selection line to the menu.
                m="$(printf '%s\n%d %s' "$m" $mc "${in/%[^[:alpha:]]*/}")"
                d1=0            # no longer looking for the 1st data line
        else    # Add another line of data to the current entry.
                d[mc]="$(printf '%s\n%s' "${d[mc]}" "$in")"
        fi
done < data
m="$(printf '%s\nEnter your choice 1 to %d (ctl-D to exit): ' "$m" $mc)"
while printf '\n%s' "$m"        # Print the menu
do      if ! read -r in         # read the user's menu selection
        then    echo            # user entered ctl-d, reposition cursor & exit
                exit
        fi
        # Verify that the user's respons was not an empty line, didn't contain
        # any non-digit characters, and is a number between 1 and $mc inclusive.
        if [[ in == '' || ${in//[[:digit:]]/} != '' || in -lt 1 || in -gt mc ]]
        then    echo 'Invalid choice.'
                continue
        fi
        # We have a verified entry, print the selected data item.
        printf '%s\n' "${d[$in]}"
        # Give the user a few seconds to read the results before reprinting the
        # menu...
        sleep 2
done

and here is the data file I used to test it:

!
version 12.4

service timestamps debug datetime msec
service timestamps log datetime msec

no service password-encryption

!
hostname MarcsTestbox
!

boot-start-marker
boot-end-marker
!
  logging message-counter syslog
        enable secret {FIELD DELETED] [FIELD DELETED]
!
no aaa new-model
clock timezone
        !
etc.
.
.



.

The first part of it is data that was provided in the 1st message in this thread, but adds some spaces and tabs at the beginning and end of some non-empty lines, and adds some blank lines to test the ability of these scripts to handle blank lines, leading whitespace, and trailing whitespace.

I hope this helps you compare some of the features of awk and ksh for performing similar tasks.

Don,

Thanks!
I need to look up "POSIX", but thank you!

Marc

Sorry, I obviously missed the ksh remark in Marc's post #1!