Break the nested while loops in unix scripting - unix

Have two files:
file1 is having the key words - INFO ERROR
file2 is having the list of log files path - path1 path2
I need to exit out of the script if any of the condition in any of the loops failed.
Here is the Code:
#!/bin/bash
RC=0
while read line
do
echo "grepping from the file $line
if [ -f $line ]; then
while read key
do
echo "searching $key from the file $line
if [ condition ]; then
RC=0;
else
RC=1;
break;
fi
done < /apps/file1
else
RC=1;
break;
fi
done < apps/file2
exit $RC
Thank you!

The ansewer to your question is using break 2:
while true; do
sleep 1
echo "outer loop"
while true; do
echo "inner loop"
break 2
done
done
I never use this, it is terrible when you want to understand or modify the code.
Already better is using a boolean
found_master=
while [ -n "${found_master}" ]; do
sleep 1
echo "outer loop"
while true; do
echo "inner loop"
found_master=true
break
done
done
When you do not need the variable found_master it is an ugly additional variable.
You can use a function
inner_loop() {
local i=0;
while ((i++ < 5)); do
((random=$RANDOM%5))
echo "Inner $i: ${random}"
if [ ${random} -eq 0 ]; then
echo "Returning 0"
return 0
fi
done;
return 1;
}
j=0
while ((j++ < 5 )); do
echo "Out loop $j"
inner_loop
if [ $? -eq 0 ]; then
echo "inner look broken"
break
fi
done
But your original problem can be handles without two while loops.
You can use grep -E "INFO|ERROR" file2 or combining the keywords. When the keywords are on different lines in file1, you can use grep -f file1 file2.

Replace condition with $(grep -c ${key} ${line}) -gt 0 like this:
echo "searching $key from the file $line
if [ $(grep -c ${key} ${line}) -eq 0 ]; then
It will count the each key-word in your log-file. If count=0 (pattern didn't found), running then. If found at least 1 key, running else, RC=1 and exit from loop.
And be sure, that your key-words can't be substrings of the longest words, or you will get an error.
Example:
[sahaquiel#sahaquiel-PC Stackoverflow]$ cat file
correctstringERROR and more useless text
ERROR thats really error string
[sahaquiel#sahaquiel-PC Stackoverflow]$ grep -c ERROR file
2
If you wish to avoid count 2 (because counting first string, obliviously, bad way), you should also add two keys for grep:
[sahaquiel#sahaquiel-PC Stackoverflow]$ grep -cow ERROR file
1
Now you have counted only the words equal to your key, not substrings in any useful strings.

Related

Version Comparison using KSH

I'm trying to write a function to compare the versions of the products.
my versions can be XX.XX.XX or xx-xx-xx either it's separated with "." or "-"
and number of fields can be different either xx.xx or xx.xx.xx or xx.xx.xx.xx
the versions which im gonna compare will identical in delimiters and with the fields
#!/bin/ksh
set -x
compareVersions ()
{
typeset IFS='.'
typeset -a v1=( $1 )
typeset -a v2=( $2 )
typeset n diff
for (( n=0; n<4; n+=1 )); do
diff=$((v1[n]-v2[n]))
if [ $diff -ne 0 ] ; then
[ $diff -le 0 ] && echo '-1' || echo '1'
return
fi
done
echo '0'
} # ---------- end of function compareVersions ----------
#compareVersions "6100-09-03" "6100-09-02"
compareVersions "6100.09.03" "6100.09.02"
Please check and give me suggestions
I have tried with the below thing which i have got a other post.. but there is no luck.. hope there should some modification should be done. I have to use across platforms ( linux, solaris, AIX ) so i have preferred KSH, i have idea only in shell scripting though.
Create arrays from version strings, then loop through them comparing elements one by one and return values accordingly. The following example will compare two version strings and returns either 0 (versions are equal), 1 (the first version string is greater) or 2 (the second version string is greater).
#!/bin/ksh
function vertest {
set -A av1 `echo $1 | sed -e 's/\'$3'/ /g'`
set -A av2 `echo $2 | sed -e 's/\'$3'/ /g'`
for (( i=0; i < ${#av1[#]}; i++ )) ; do
[[ ${av1[$i]} -eq ${av2[$i]} ]] && continue
[[ ${av1[$i]} -gt ${av2[$i]} ]] && return 1
[[ ${av1[$i]} -lt ${av2[$i]} ]] && return 2
done
return 0
}
v1="2-7-2-1"
v2="1-8-0-1"
vertest $v1 $v2 '-'
exit $?
# end of file.
This example will exit to shell with exit code 1. Should you change $v1 to 1-7-2-1, it will exit to shell with exit code 2. And so on, and so forth.
The separator escaping is not complete, but this works with most reasonable separators like a period (.) and a dash (-). This, as well as parameter checking for the vertest() is left as an exercise for the reader.
When the format of both numbers is equal (leading zero as your example), you can use
compareVersions ()
{
val1=$(echo $1| tr -d ".-")
echo ${val1}
val2=$(echo $2| tr -d ".-")
echo ${val2}
if [ ${val1} -gt ${val2} ] ; then
echo 1
return
fi
if [ ${val1} -eq ${val2} ] ; then
echo 0
return
fi
echo '-1'
} # ---------- end of function compareVersions ----------

Unix determine if a file is empty

I am attempting to make a script that will check to see if there is any tyext within a file. I have developed the following script. I have made it check to see if there is exactly 2 arguments, see if the file exists, but I am having trouble checking the file for text within it. The code is as follows:
#!/bin/ksh
#check if number of arguments are 2
if [ $# -ne 2 ]; then
echo "Does not equal two arguments"
echo "Usage $0 inputfile outputfile"
exit 1
fi
#check if input file exists
if [ ! -f $1 ]; then
echo "$1 not found!"
exit 1
fi
#Check if input file is null
#This next block of code is where the issue is
if [ grep -q $1 -eq 0 ]; then
echo "$1 must have text within the file"
exit 1
fi
Any help would be appreciated
test's "-s" option checks if the file is empty -- see manual. So your last chunk would become
#Check if input file is null
#This next block of code is where the issue is
if [ ! -s $1 ]; then
echo "$1 must have text within the file"
exit 1
fi
Try using stat
stat -c %s filename

List files from directory without displaying them

I am writing a script where I need to list files without displaying them. The below script list the files while executing which I don't want to do. Just want to check if there are files in directory then execute "executing case 2".
ls -lrt /a/b/c/
if [ $? != 0 ]
then
echo "executing case 2"
else
echo "date +%D' '%TNo files found to process" >> $LOG
Testing the return code of ls won't do you a lot of good, because it'll return zero in both cases where it could list the directory.
You could do so with grep though.
e.g.:
ls | grep .
echo $?
This will be 'true' if grep matched anything (files were present). And false if not.
So in your example:
ls | grep .
if [ $? -eq 0 ]
then
echo "Directory has contents"
else
echo "directory is empty"
fi
Although be cautious with doing this sort of thing - it looks like you're in danger of a busy-wait test, which can make sysadmins unhappy.
If you don't need to see the output of ls, you could just make it a condition:
[ "$(ls -lrt a/b/c)" ] && echo "Not Empty" || echo "Empty"
Or better yet
[ "$(ls -A a/b/c)" ] && echo "Not Empty" || echo "Empty"
Since you don't care about long output (l) or display order (rt).
In a script, you could use this in an if statement:
#!/bin/sh
if [ "$(ls -A a/b/c)" ]; then
echo "Not empty"
else
echo "Empty"
fi

if [ $? -ne 0 ] then syntax error then unexpected

I have been trying to execute the following UNIX shell script which is not working.
I am running it by KornShell (ksh).
echo $?;
if [ $? -ne 0 ]
then
failed $LINENO-2 $5 $6
fi
failed()
{
echo "$0 failed at line number $1";
echo "moving $2 to failed folder"
}
This is giving an error saying Syntax error:then unexpected.. Basically I have to check for the last executed ksh script's highest/last statement's return code and if it is not equal to zero I have to call function failed with the given parameters. I tried putting semicolon before then but that also did not work.
Can you please help?
Edit1: Based on the inputs I changed code. Still the same problem exists.
ksh ../prescript/Pre_process $1 $2 $3
rc=$?;
if [[ $rc -ne 0 ]];then
echo "failed";
exit 1;
Edit2:
It is working for the then part by using double squared brackets. I feel I used code of bash script for ksh. I am facing problem in function call of failed. Please let me know appropriate way of function call in ksh for this example
This looks like bash rather than ksh
failed() {
echo "$0 failed at line number $1";
echo "moving $2 to failed folder"
}
if [[ $? -ne 0 ]]
then
failed $LINENO-2 $5 $6
fi
You need to be careful. The first operation on $? will usually clear it so that your if won't work anyway.
You would be better off using:
rc=$?
echo $rc
if [ $rc -ne 0 ]
:
Other than that, it works fine for me:
$ grep 1 /dev/null
$ if [ $? -ne 0 ]
> then
> echo xx
> fi
xx
$ grep 1 /dev/null
$ echo $?;
1
$ if [ $? -ne 0 ]
> then
> echo yy
> fi
$ _
Note the lack of output in the last one. That's because the echo has sucked up the return value and overwritten it (since the echo was successful).
As an aside, you should let us know which UNIX and which ksh you're actually using. My working version is ksh93 under Ubuntu. Your mileage may vary if you're using a lesser version.
It looks like, from your update, your only problem now is the function call. That's most likely because you're defining it after using it. The script:
grep 1 /dev/null
rc=$?
if [ $rc -ne 0 ]
then
failed $rc
fi
failed()
{
echo Return code was $1
}
produces:
qq.ksh[6]: failed: not found
while:
failed()
{
echo Return code was $1
}
grep 1 /dev/null
rc=$?
if [ $rc -ne 0 ]
then
failed $rc
fi
produces
Return code was 1
you are missing semicolons at the end of the lines:
if [ $? -ne 0]; then
# …

How to use loops statements in unix shell scripting

How to use loop statements in unix shell scripting for eg while ,for do while. I'm using putty server.
for: Iterate over a list.
$for i in `cat some_file | grep pattern`;do echo $i;done
while loop looks pretty much like C's.
$ i=0;while [ $i -le 10 ];do echo $i;i=`expr $i + 1` ;done
If you are going to use command line only, you could use perl, but I guess this is cheating.
$perl -e '$i=0;while ($i < 10){print $i;$i++;}'
More data
http://www.freeos.com/guides/lsst/
#!/bin/sh
items=(item1 item2 item3)
len=${#items[*]}
i=0
while [ $i -lt $len ]; do
echo ${items[$i]}
let i++
done
exit 0
As well as the 'for' and 'while' loops mentioned by Tom, there is (in classic Bourne and Korn shells at least, but also in Bash on MacOS X and presumably elsewhere too) an 'until' loop:
until [ -f /tmp/sentry.file ]
do
sleep 3
done
This loop terminates when the tested command succeeds, in contrast to the 'while' loop which terminates when the tested command fails.
Also note that you can test a sequence of commands; the last command is the one that counts:
while x=$(ls); [ -n "$x" ]
do
echo $x
done
This continues to echo all the files in the directory until they're all deleted.
to the OP, to iterate over files
for file in *
do
echo "$file"
done
to generate counters
for c in {0..10}
do
echo $c
done
using for loop
max=10
for (( i=0; i<=$max; i++ ));
do
echo $i
done
to iterate through a file in KSH
while read line ; do
echo "line from file $line"
done < filename.txt
echo "sample while loop"
i=0;
while [ $i -le 10 ]
do
echo $i
(( i++ ))
done

Resources