# Taking input line by line from a config file in Bash



## Matthew_S (May 24, 2007)

Hi all and firstly Happy New Year!

It wouldnt be a New Year without a New Problem though ;-)

Im trying to create a script that will take the input of a config file line by line. Unfortunately, what seems to be happening is that it is taking it though word by word instead?

For arguments sake Ive put I want this whole line on one line into the config file and the script looks like this;

for i in `cat config.txt`
do echo $i
echo >> $RESULTS
echo $i >> $RESULTS
$i
[ $? == 0 ] && echo "PASSED" >> $RESULTS || echo "FAILED" >> $RESULTS
Done

And here are the results;

I
./filesystem_test.sh: line 12: I: command not found
want
./filesystem_test.sh: line 12: want: command not found
this
./filesystem_test.sh: line 12: this: command not found
whole
./filesystem_test.sh: line 12: whole: command not found
line
./filesystem_test.sh: line 12: line: command not found
on
./filesystem_test.sh: line 12: on: command not found
one
./filesystem_test.sh: line 12: one: command not found
line
./filesystem_test.sh: line 12: line: command not found

Its been suggested that I try read and so I have this;

File=./config.txt

{
read line
echo $i
echo >> $RESULTS
echo $i >> $RESULTS
$i
[ $? == 0 ] && echo "PASSED" >> $RESULTS || echo "FAILED" >> $RESULTS
} < $File

But need to get the numbered input from by using cat -n on the config file, but the space delimiter in cut doesnt seem to allow me to select only the numbers? Which means I cant run something like;

for i in `cat -n config.txt | cut -d' ' -f1
do read line $i
etc

Any help or guidance would be greatly appreciated.

Many thanks.

Matthew.


----------



## Matthew_S (May 24, 2007)

Sorted... the answer is;

cat $File | # Supply input from a file.
while read line # As long as there is another line to read ...

do echo $line
echo >> $RESULTS
echo $line >> $RESULTS
$line
[ $? == 0 ] && echo "PASSED" >> $RESULTS || echo "FAILED" >> $RESULTS
done

exit

Thanks all.


----------



## RobLinux (Nov 7, 2007)

Doesn't a syntax error in the input file, cause your script to abort?

I'd expect you to need to eval each linem rather than execute $line directly (but perhaps your loop makes it fail gracefully). For instance using a silly example :

[email protected]:~> cat t.sh
if 1
echo 2
case $? each
esac

echo 5 && echo AOK
[email protected]:~> bash -x t.sh
t.sh: line 3: syntax error near unexpected token `each'
t.sh: line 3: `case $? each'
[email protected]:~> 

The stuff after 1st error doesn't get done, wheras when you use 'eval' :

[email protected]:~> cat et.sh
eval "if 1
echo 2
case $? each
esac"

eval echo 5 && echo AOK
[email protected]:~> !ba
bash -x et.sh
+ eval 'if 1
echo 2
case 0 each
esac'
et.sh: eval: line 6: syntax error near unexpected token `each'
et.sh: eval: line 6: `case 0 each'
+ eval echo 5
++ echo 5
5
+ echo AOK
AOK
[email protected]:~>


----------



## Matthew_S (May 24, 2007)

No, it doesn't fail with any syntax errors. However, since this morning I've refind the script and it now looks like this;

...
while read line # As long as there is another line to read ...
do
{
echo
$line > /dev/null && echo $line "PASSED" || echo $line "FAILED"
} >> $RESULTS
done < $FILE
exit 0

And here's a sample from the config.txt;

ls -z
cp config.txt configcopied.txt
rm configcopied.txt
ls -l | cut -d f -f 1
dd if=config.txt of=ddfile.test bs=1024 count=10

And the relevant results;

ls -z FAILED

cp config.txt configcopied.txt PASSED

rm configcopied.txt PASSED

ls -l | cut -d f -f 1 FAILED

dd if=config.txt of=ddfile.test bs=1024 count=10 PASSED

And the errors that are shown on the CLI

ls: invalid option -- z
Try `ls --help' for more information.

ls: |: No such file or directory
ls: cut: No such file or directory
ls: f: No such file or directory
ls: 1: No such file or directory

What is odd here, and I haven't gotten around to figuring it out yet, is why 'ls -l | cut -d f -f 1' failed? If I run 'ls -l | cut -d f -f 1' on the CLI it runs fine, but fails when run via the script...


----------



## RobLinux (Nov 7, 2007)

As a matter of interest, have you tried feeding syntactically incorrect input into the File?
See there's a general issue with running commands from "untrusted" input, and none of those errors are shell syntax errors. But likely, because you're executing a variable, the 'eval' is done implicitly.

Anyway as you're interested in improving the script. 

echo2 () {
echo "[email protected]" 2>&1
}

Let's you write to stderr with stdout redirect for messages. So you could call echo2 "", echo2 $line PASSED or $line FAILED, and re-direct stdout once to /dev/null and error to the logfile outside the loop, something like (foobar > /dev/null) >>& $RESULTS, where foobar is your special purpose interpreter.


----------



## Matthew_S (May 24, 2007)

I tried feeding the syntactically incorrect input as per your example in your first post;

case $? each

And the stderr was;

./filesystem_test.sh: line 14: case: command not found

And the results file reported that;

case $? each FAILED

Do you have anyother examples of syntactically incorrect input that you think may trip it up?

With regards to you second point, I have to let you know that I'm relatively new to this whole Linux and Bash thing, so I'm having a little difficulty deciphering what it is you've exactly said. Correct me if I'm wrong;

That piece of code will direct the stderr, the error which is normally printed on screen, the./filesystem_test.sh: line 14: case: command not found text, to the log file 'results' whilst also redirecting the stdout, everything else that would be printed to screen which I've already redirected to /dev/null, to /dev/null?

Where in the scipt would I place it?


----------



## RobLinux (Nov 7, 2007)

That was a demo of a "shell procedure", declaring something like, lets you call it later, as if it were a command or a builtin. Unfortunately doing quick replies here, formatting tends to get messed up, reducing clarity.

echo2 () {
echo "[email protected]" 2>&1
}

echo2 Print on Std Error

You don't say whether the input causes things to bomb out or not. Anyway in past examples, doing similar things in say backup scripts, eval was useful to built up the commandlines, and tends to work better with for loops, as you interate on a list of things. But it may not be necessary in bash.


----------

