Bash on Windows while loop - windows

I am attempting to port a shell script to run on GNU for Windows, which provides a bash shell for Windows. I've run into an issue:
while [ $no -le $number ]
doesn't seem to register. As a test, I tried
no=1
number=10
echo debug1
while [ $no -le $number ]
do
echo debug2
no=$((no+1))
done
echo debug3
This returns debug1 and debug3, so it doesn't seem to even enter the loop.
no=1
echo debug1
while [ $no -le 10 ]
do
echo debug2
no=$((no+1))
done
echo debug3
This, on the other hand, works, and gives me debug1, 10 debug2s, and debug3.
I'm guessing it's a syntax error, but I'm not sure how to fix this. Any suggestions?

That works fine (as it should) under bash in Linux, and even under the relatively ancient bash I have in CygWin:
pax> number=10
pax> no=1 ; while [ $no -le $number ] ; do echo $no ; no=$((no+1)) ; done
1
2
3
4
5
6
7
8
9
10
My only suggestion is to print out the two variables before you attempt to enter the while loop, and after the no=$((no+1)) line, in case there's something wrong, something like:
echo "[$no] [$number]"
You may also want to put a set -x at the top of your script as it will output each interpreted line before trying to execute it.

Related

Bash Script stuck looping

I'm trying to write a script that runs another script which fails rarely until it fails.
Here is the script that fails rarely:
#!/usr/bin/bash
n=$(( RANDOM % 100 ))
if (( n == 42 )) ; then
echo "$n Something went wrong"
>&2 echo "The error was using magic numbers"
exit 1
fi
echo "$n Everything went according to plan"
Here is the script that should run the previous script until it fails:
#!/usr/bin/bash
script_path="/tmp/missing/l2q3.sh"
found=0
counter=0
while (( $found == 0 )); do
output=(bash $script_path)
if (( $output == 42 Something went wrong )); then
found=1
fi
((counter++))
if (( $found == 1 )); then
echo "Number 42 was found after $counter tries"
fi
done
when I try running the second script I get stuck in an infinite loop saying there is a syntax error on line 11 and that something is wrong with 42 Something went wrong. I've tried with "42 Something went wrong" aswell and still stuck in a loop.
The form (( )) is arithemetic only, so you cannot test a string inside.
To test a string, you have to use the [[ ]] version:
[[ $output == "42 Something went wrong" ]] && echo ok
ok
You can use the program execution as the test for a while/until/if (etc.)
Assuming your script returns a valid 0 error code on success, and nonzero on any other circumstance, then -
$: cat tst
#!/bin/bash
trap 'rm -fr $tmp' EXIT
tmp=$(mktemp)
while /tmp/missing/l2q3.sh >$tmp; do let ++ctr; done
grep -q "^42 Something went wrong" $tmp &&
echo "Number 42 was found after $ctr tries"
In use:
$: ./tst
The error was using magic numbers
Number 42 was found after 229 tries
here are 3 steps to move forward.
add a return value at the end of the first script
exit 0
make your first script has executable rights
$ chmod a+x /tmp/missing/12q3.sh
instead of while loop you may use until, which would run until it returns success i.e. 0
until /tmp/missing/l2q3.sh; do ((counter++)) done
for other if statements please use square brackets [ single or double [[.

Assigning variables which contain variable

I have three files named /opt/Process1.txt, /opt/Process2.txt, and /opt/Process3.txt. I would like to assign the contents of each file to a variable respectively. I have tried:
Num=1
while [ $Num -le 3 ]
do
Pass${Num}=`cat /opt/Process${Num}`
#There is some other stuff but the above is the issue
Num=`expr $num + 1`
done
It looks like the system is trying to output the content when executed
If I try a static number it is ok I.e
Pass1=`cat /opt/Process1`
Pass2=`cat /opt/Process2`
Pass3=`cat /opt/Process3`
Any help would be appreciated.
It looks like the shell tries to run Pass1=blablabla as an executable, which does not exist (command not found).
You can work around this using declare:
declare "Pass${Num}=`cat /opt/Process${Num}`"
Here is my code corrected and your code made to work
for Num in `seq 1 3`
do eval Pass${Num}="$(cat /tmp/Process${Num})"
done
echo $Pass1 $Pass2 $Pass3
Num=1
while [ $Num -le 3 ]
do
eval Pass${Num}=`cat /opt/Process${Num}`
#There is some other stuff but the above is the issue
Num=`expr $num + 1`
done
Using the answer provided by Thomas
for Num in `seq 1 3`
do declare Pass${Num}="$(cat /tmp/Process${Num})"
done
echo $Pass1 $Pass2 $Pass3
Num=1
while [ $Num -le 3 ]
do
declare Pass${Num}=`cat /opt/Process${Num}`
#There is some other stuff but the above is the issue
Num=`expr $num + 1`
done
Here I run into the same issue
If you really are only incrementing up by one from 1 to 3 you could also do
for num in `seq 1 3`
do
Pass${Num}=`cat /opt/Process${Num}`
#There is some other stuff but the above is the issue
done

Count number of occurrences in file. conditional pattern matching

Sorry if the title doesn't make it clear.
I have a file to be read every 15 mins and find a particular pattern in it (e.g. timeout). File does not have any fixed update frequency.
Outcome expected:-
1. if pattern is found 3 times in 15 mins, run command1.
2. if pattern is found 5 times in 15 mins, run command2.
File to be read from last read position for each check.
Thanks,
GRV
One way to do this is with a cron job. It is more complicated than other solutions but it is very reliable (even if your "check script" crashes, it will be called up again by cron after the period elapses). The cron could be:
*/15 * * * * env DISPLAY=:0 /folder/checkscript >/dev/null 2>&1
The env DISPLAY=:0 might not be needed in your case, or it might be needed, depending on your script (note: you might need to adapt this to your case, run echo $DISPLAY to find out your variable on the case).
Your "checkscript" could be:
#!/bin/bash
if [ -f /tmp/checkVarCount ]; then oldCheckVar="$(cat /tmp/checkVarCount)"; else oldCheckVar="0"; fi
checkVar="$(grep -o "pattern" /folder/file | wc -l)"
echo "$checkVar" > /tmp/checkVarCount
checkVar="$(($checkVar-$oldCheckVar))"
if [ "$checkVar" -eq 3 ]; then command1; fi
if [ "$checkVar" -eq 5 ]; then command2; fi
exit
It is not included on your question, but if you meant to run the commands as well if the pattern is found 4 times or 7 times, then you could change the relevant parts above to:
if [ "$checkVar" -ge 3 ] && [ "$checkVar" -lt 5 ]; then command1; fi
if [ "$checkVar" -ge 5 ]; then command2; fi

No such file or directory error

counter=0
if [ ${counter} < 10 ]; then
echo 10
fi
error : no such file or directory.
What wrong in there ?
Instead of using the < symbol (which is for shell redirection) you need to use the -lt option to test.
counter=0
if [ ${counter} -lt 10 ]; then
echo 10
fi
With the <, the shell is actually trying to read in a file named 10 to stdin of the command [ ${counter} (aka test ${counter}).
man test is one of those things I constantly refer back to just to reassure myself.

Loop in UNIX is not working

Please tell me what is wrong with the UNIX code below.
#!/bin/ksh
p=10
for i in $p
do
echo $i
done
i am expecting output as
1
2
3
.
.
.
but the output am getting is just 10
I need for loop not while loop.
in ksh
#!/bin/ksh
p=10
i=1
while ((i<=p)); do
echo $i
i=$((i+1))
done
or
#!/bin/ksh
# with for you can only do this
for i in 1 2 3 4 5 6 7 8 9 10; do
echo $i
done
in bash it works as expected
#!/bin/bash
p=10
for (( i=1; i<=p; i++ )); do
echo $i
done
there is a Linux command seqthat can be used for both ksh and bash. But it is a Linux command. So this will not work on Solaris or other Unix systems that don't have the progrtam seq installed.
# on Linux, bash or ksh
p=10
for i in $(seq $p); do
echo $i
done
The following uses only shell built-ins and therefore will work for all bash installations (e.g. on Solaris) but not for ksh
#!/bin/bash
p=10
for i in `eval echo {1..$p}`; do
echo $i
done
This complicated construct is necessary because of brace expansion occurrs before variable expansion
You have to assign a range. Otherwise the loop can't work. This should do it:
#!/bin/ksh
p=10
for i in {0..$p}
do
echo $i
done
#fedorqui: You are right, I absolutely missed that. When I do stuff like this in Bash (I don't know if it's the same for KornShell), I go like:
for ((i=0; i<$p; i++))
in UNIX KSH
#!/bin/ksh
while [ ${i:=1} -le 10 ]
do
echo "$i"
let i+=1
done

Resources