file feed one line per argument

What tools can I use to accomplish this?
I'm writing a shell script to analyze an inittab file. Here's a sample file:

init:3:initdefault:
ioin::sysinit:/sbin/ioinitrc >/dev/console 2>&1
tape::sysinit:/sbin/mtinit > /dev/console 2>&1
muxi::sysinit:/sbin/dasetup </dev/console >/dev/console 2>&1 # mux i
nit
stty::sysinit:/sbin/stty 9600 clocal icanon echo opost onlcr ixon icrn
l ignpar </dev/systty
brc1::bootwait:/sbin/bcheckrc </dev/console >/dev/console 2>&1 # fsck,
etc.
link::wait:/sbin/sh -c "/sbin/rm -f /dev/syscon; \
/sbin/ln /dev/systty /dev/syscon" >/dev/consol
e 2>&1
cprt::bootwait:/sbin/cat /etc/copyright >/dev/syscon # legal
req
sqnc::wait:/sbin/rc </dev/console >/dev/console 2>&1 # syste
m init
#powf::powerwait:/sbin/powerfail >/dev/console 2>&1 # power
fail
cons:123456:respawn:/usr/sbin/getty console console # syste
m console
#ttp1:234:off:/usr/sbin/getty -h tty0p1 9600 # UPS now using this port
#ttp2:234:respawn:/usr/sbin/getty -h tty0p2 9600
#ttp3:234:respawn:/usr/sbin/getty -h tty0p3 9600
#ttp4:234:respawn:/usr/sbin/getty -h tty0p4 9600
#ttp5:234:respawn:/usr/sbin/getty -h tty0p5 9600
ems1::bootwait:/sbin/rm -f /etc/opt/resmon/persistence/runlevel4_flag
ems2::bootwait:/sbin/cat </dev/null >/etc/opt/resmon/persistence/reboo
t_flag
ems3:3456:wait:/usr/bin/touch /etc/opt/resmon/persistence/runlevel4_fl
ag
ems4:3456:respawn:/etc/opt/resmon/lbin/p_client
ups::respawn:rtprio 0 /usr/lbin/ups_mond -f /etc/ups_conf

I want to read each line, and do various things, (i.e. ignore lines that begin with #)but what will send each line as an argument?

The basic strategy woudl be to read each
line in a loop:

!#/bin/sh

while read iline
do
echo $iline
done < /etc/inittab

exit 0

In each iteration of the loop, you have the
entire line in the variable $iline.
From this point, the next step is to process
each line in the loop however you need to.
You can use awk for this task if you desire.

I just gave you the very basics as to not give
away all the answers but it's a least a starting
point :wink:

thanks rwb, exactly what i was looking for. but i'm stuck there now. i was planning to use grep to anaylze inittab, you know, grep lines that begin with a # and ignore them, check the fields...
but how can I pass each line as the argument to grep?
I tried this way, but i'm not quite where I need to be yet:

#!/bin/ksh

while read iline
do
echo $iline|xargs
echo $*
grep ^# $*

as you can see, I"m using the Korn shell..

any more help will be greatly appreciated,

thanks again

I would use a different approach. I would
use grep to remove all the lines that
start with "#"...

!#/bin/ksh

# create a tmp file with all lines in /etc/inittab
# that do not start with "#"
grep -v ^# /etc/inittab > /tmp/mytest.$$

#loop through each line in the tmp file
while read iline
do
# this is where you would process $iline
# using awk and/or sed is easiest IMHO
...
...
done < /tmp/mytest.$$

# clean up after yourself
rm -f /tmp/mytest.$$

exit 0

...what you do in the processing of each line
is dependent on what "and do various things"
entails. I'd also recommend a careful reading
of the grep man page. There's alot of good stuff
you can do with it. Also, the following URL
is a good online reference for AWK:
http://vectorsite.tripod.com/tsawk0.html

I'll use sed and awk when I get more familiar with them, I think grep will work for what I need to do, here's my script so far, with some of the "various things" I want the loop to do included as comments. Your help has made a drastic improvement already, what will the next step be...

#!/bin/ksh

# Usage: chkinit (inittab file)

# This creates a temp file to work with,using all lines
# in the inittab that do not begin with # (assumes the argument is an
# inittab file) and all lines that are not blank

grep -v -e "^#" -e "^$" $1 > /tmp/mytest.$$

# this will loop through each line in the tmp file

while read iline
do
# case (can I use case here... if so how?)
# I would like to: * ensure that all lines contain 4 fields
# * make sure the id field has from 1 to 4 chars
# * make sure that the run levels are valid for
the process indicated
done < /tmp/mytest.$$

rm -f /tmp/mytest.$$

Well... I don't believe grep by itself will
give you what you need. This is why I suggest
awk. I myself would in fact use awk for this
sort of thing. ksh itself does not provide
good string handling capabilities (at least not
without alot of excess work). For example,
the resulting lines from /etc/initab may be
somthing like...

1:2345:respawn:/sbin/mingetty tty1
2:2345:respawn:/sbin/mingetty tty2
3:2345:respawn:/sbin/mingetty tty3
...
...

...so here you can see you have 4 fields...
id:runlevels:action:process
...separated by a ":" and you need to examine
these individually so you would need to
separate each field into distinct variables.
awk provides simple methods for doing this
very thing (and much much more). You could
perhaps use "case" against a single field
variable (once extracted from the line) to
apply rules that are defined as general for
a given value. Special rules however will
tend to create an overly complex script and
more prone to errors.

Again, my recommendation would be to learn
awk (at least the basics of it) and try some
things. After that if you have more questions,
I'm sure you can get answeres on this forum.:slight_smile:

I would just use ksh by itself. It can read each record, split the record into fields, count the characters in a field, etc. In short, it can do everything you need.

Also, remember that lines are not the same as records in inittab. You can end a line with a backslash to continue the record on the next line. Your grep method doesn't handle this.

Here is some sample code to show the concept...

#! /usr/bin/ksh

IFS=":"
while read id rstate action process ; do

#  ignore comments
    [[ $id = \#* ]] && continue

#  count fields
    ((nf=0))
    [[ ! -z $id      ]]  && ((nf=nf+1))
    [[ ! -z $rstate  ]]  && ((nf=nf+1))
    [[ ! -z $action  ]]  && ((nf=nf+1))
    [[ ! -z $process ]]  && ((nf=nf+1))

#  ignore all blanks
    (( ! nf )) && continue

    idlength=${#id}
    echo $id $idlength
done
exit 0

You should be able to code in any tests you want in place of that echo statement.

wow, thanks. that's getting there, but the -z won't allow for empty fields, which i think are legal, like this line:

ups::respawn:rtprio 0 /usr/lbin/ups_mond -f /etc/ups_conf

doesn't a blank in the runlevel field indicate this should run at all run levels?

Yeah, that line is legal and my code will not reject it. It this case nf will be 3 because there are 3 non-empty fields. Only records where nf is 0 are discarded, these are blank lines.

If you leave this field empty, it is the same as specifying "0123456", which means that it will not run in run level s.

I see that it works. But somehow I have to count the empty fields, to make sure that there are 4 fields, empty or not. I tried adding an "or" to the test statement (for fields 2 and 4, which can be blank), like this:

[[ ! -z $rstate -o -z $rstate ]] && ((nf=nf+1))

but it complains about the -o option.

This is the test I put for length of id field,
thanks again.

    idlength=$\{\#id\}      

    if [ $idlength -ne 0 -a $idlength -le 4 ]; then
    :
    else
    echo "id field must be from 1 to 4 characters"
    fi

I also need some way to put the line number of a failing line into an echo statement...

Don't do that. The nf stuff is to detect completely blank lines. If you really wanted to unconditionally increment nf at this point, there is no need to add a test that cannot fail. ((nf=nf+1)) could be used all by itself. Add with ksh [[ or it handled by | not -o.

If you don't care whether or not the field rstate has something, just don't test it. Instead, test the stuff you do care about. You are already checking the id field for the number of characters. That leaves the action field. You can just add a "if [[ -z $action ]]" or maybe you'd rather get the length of the action field and see if it's non-zero.