How to break out of infinite while loop in a shell script?
I want to implement the following PHP code in shell script(s):
$i=1;
while( 1 ) {
if ( $i == 1 ) continue;
if ( $i > 9 ) break;
$i++;
}
break works in shell scripts as well, but it's better to check the condition in the while clause than inside the loop, as Zsolt suggested. Assuming you've got some more complicated logic in the loop before checking the condition (that is, what you really want is a do..while loop) you can do the following:
i=1
while true
do
if [ "$i" -eq 1 ]
then
continue
fi
# Other stuff which might even modify $i
if [ $i -gt 9 ]
then
let i+=1
break
fi
done
If you really just want to repeat something $count times, there's a much easier way:
for index in $(seq 1 $count)
do
# Stuff
done
i=1
while [ $i -gt 9 ] ; do
# do something here
i=$(($i+1))
done
Is one of the ways you can do it.
HTH
Related
Create bash for loop with two alternative starts. I would like to either iterate through all numbers in a range or all elements in an array depending on a condition. The following unorthodox code shows the example:
#!/bin/bash
FROMVAL=1
TOVAL=5
VALARR=(1 3 5)
ISCONSEQ=1
if (( ISCONSEQ == 1 )); then
for (( counter=$FROMVAL; counter<=$TOVAL; counter++ ))
else
for counter in "${VALARR[#]}"
fi
do
echo $counter
done
Obviously, this does not work nor is it pretty. Is there a bash way to do this or should I create two for loops and execute only one depending on the content of ISCONSEQ? Or should I use a for...in loop for both cases and simply assign the values of my sequence to the array?
This code does work but relies only on the array:
if (( ISCONSEQ == 1 )); then
VALARR=($(seq $FROMVAL 1 $TOVAL))
fi
for counter in "${VALARR[#]}"
do
echo $counter
done
This is a good use case for a function. Create function for the echo and call it from each for loop. It would look like this.
#!/bin/bash
FROMVAL=1
TOVAL=5
VALARR=(1 3 5)
ISCONSEQ=1
function dostuff() {
echo $*
}
if (( ISCONSEQ == 1 )); then
for (( counter=$FROMVAL; counter<=$TOVAL; counter++ ))
do
dostuff $counter
done
else
for counter in "${VALARR[#]}"
do
dostuff $counter
done
fi
First, I agree with the previous comments that 2 for loops is not as offensive as it may look.
Second, you can't conditionally kick off a for loop in the manner of your example. But, you can manipulate your array with a conditional.
So to satisfy your question, here would be a simple solution:
FROMVAL=1
TOVAL=5
VALARR=(1 3 5)
ISCONSEQ=0
if (( ISCONSEQ != 1))
then
VALARR=($(seq $FROMVAL 1 $TOVAL))
fi
for counter in "${VALARR[#]}"
do
echo "$counter"
done
I have the below scenario.
I'm iterating through array elements in bash and comparing the values.
#!/bin/bash
for (( i = 0 ; i <=m-1 ; i++));
do for (( j = 0 ; j <=n-1 ; j++));
do
if [ "${sourcedisktype[i]}" == "SSD" -a "${targetdisktype[j]}" == "BSAS" ];
then echo "volume cannot be moved1";
elif [ "${sourcedisktype[i]}" == "SSD" -a "${targetdisktype[j]}" == "SAS" ];
then echo "volume cannot be moved2";
elif [ "${sourcedisktype[i]}" == "SAS" -a "${targetdisktype[j]}" == "BSAS" ];
then echo "volume cannot be moved3";else
echo "Volume can be moved for this combination of disk type";done;done;
I don't want to execute the else part even if one elif fails. Is there any way to do it. Is it possible to use break statement after elif?
Of course you can break out of your loops in bash, you can actually even break out of N nested loops if you use the statement break N where N is an integer >=1.
For more details please have a look at the documentation:
http://tldp.org/LDP/abs/html/loopcontrol.html
You can actually also use continue N but it can be quite tricky and hard for others to understand, so I would not recommend to use it.
PS: do not forget to indent your code properly in order for others to understand it quickly and even for yourself, I can affirm that it will be a pain if you try to reread your code in a couple of months/years. You will regret not having indented/commented it properly.
Is there a way to end a while loop by using an if? Here's just some pseudocode of the basics of what I want to do:
re = 1
while [re = 1]
do
echo "hello, enter name"
read name
echo name
echo "continue? 1 for yes, 0 for no"
read re
if [re == 1]
then
pass
elif [re == 0]
then
end while
else
pass
It looks like you need to use continue in place of pass if you want to skip the rest of the loop and start again from the beginning, and you need to use break instead of end while if you want to exit the loop altogether.
Yes, bash supports the break command to do that:
i=0;
while [ $i -lt 10 ]; do
if [ $i -eq 3 ]; then
break
fi
echo $i
let i++
done
Will output:
0
1
2
I need some help from this awesome community.
I'm trying to write a script that loops through each word of a sentence stored in a variable (for example SENTENCE).
Example:
for WORD in $SENTENCE
do
echo do something
done
The problem that I'm facing is that I need to change the value of WORD to restart the loop if a certain condition is true inside the loop.
Example:
for WORD in $SENTENCE
do
echo do something
if [[ $SOMETHING_HAPPENED == TRUE ]]; then
WORD=$FIRST_WORD_IN_SENTENCE
fi
done
Basically, I need to restart the loop if certain conditions are met (SOMETHING_HAPPENED), but I don't know how to do this properly.
If this was a normal C loop I would do it like this:
for (i=0;i<10;i++){
do_something();
if (SOMETHING_HAPPENED == TRUE){
i=0;
}
}
How do I do this in shell script?
Thank you.
You could use a loop around your for loop that executes the for loop until the something doesn't happen:
repeat=yes
while [ "$repeat" = yes ]; do
repeat=no
for WORD in $SENTENCE; do
# do something
if [[ $SOMETHING_HAPPENED == TRUE ]]; then
repeat=yes
break
fi
done
done
while [[ 1 ]]; do # infinite loop
for word in $sentence; do
…
if [[ $condition ]]; then
continue 2 # go to the next iteration of the *outer* loop
fi
done
break # escape the outer loop
done
To restart the loop you can use BASH arrays and run your loop like this:
arr=( $sentence )
for ((i=0; i<${#arr[#]}; i++)); do
word="${arr[$i]}"
# evaluate condition
if [[ "$SOMETHING_HAPPENED" == TRUE ]]; then
i=0
continue
fi
echo "$word"
done
I want to use subshells for making sure environment changes do not affect different iterations in a loop, but I'm not sure I can use loop control statements (break, continue) inside the subshell:
#!/bin/sh
export A=0
for i in 1 2 3; do
(
export A=$i
if [ $i -eq 2 ]; then continue ; fi
echo $i
)
done
echo $A
The value of A outside the loop is unaffected by whatever happens inside, and that's OK. But is it allowed to use the continue inside the subshell or should I move it outside? For the record, it works as it is written, but maybe that's an unreliable side effect.
Just add
echo "out $i"
after the closing parenthesis to see it does not work - it exits the subshell, but continues the loop.
The following works, though:
#! /bin/bash
export A=0
for i in 1 2 3; do
(
export A=$i
if [ $i -eq 2 ]; then exit 1 ; fi
echo $i
) && echo $i out # Only if the condition was not true.
done
echo $A
Can you simply wrap the entire loop in a subshell?
#!/bin/sh
export A;
A=0
(
for i in 1 2 3; do
A=$i
if [ $i -eq 2 ]; then continue ; fi
echo $i
done
)
echo $A
Note also that you don't need to use export every time you assign to the variable. export does not export a value; it marks the variable to be exported, so that any time a new process is created, the current value of that variable will be added to the environment of the new process.