Difference between continue and colon in conditional statement - bash

What is the difference between using a colon, which means "do nothing" and continue, which means skip.
if [[ -s $file ]] ; then
:
fi
if [[ -s $file ]] ; then
continue
fi

: is a synonym for true. It does not prevent later commands in the same block or loop from running.
Compare:
for (( i=0; i<3; i++ )); do
echo "Starting iteration $i"
(( i == 1 )) && { echo " About to run :"; :; echo " Just ran :"; }
(( i == 2 )) && { echo " About to run continue"; continue; echo " Just ran continue"; }
echo "Ending iteration $i"
done
Our output is:
Starting iteration 0
Ending iteration 0
Starting iteration 1
About to run :
Just ran :
Ending iteration 1
Starting iteration 2
About to run continue
Note that we made it to "ending" after running :, but not after running continue.

It depends on your program's logic.
Outside of a loop you get
$ continue
bash: continue: only meaningful in a `for', `while', or `until' loop

Related

loop in bash does not perform integer comparison properly

I have below code
i=0
for s in / - \\ \|
do
printf "\rWaiting for application start to finish $i $s"
sleep 1
((i++))
if [[ $i -gt 30 ]]
then
break
fi
done
The loop always ends after 3 iterations. Any reason as why?
This might be what you are looking for:
#!/bin/bash
a=('/' '-' '\' '|')
for ((i = 0; i < 30; ++i)); do
printf '\rWaiting for application start to finish %d %s' \
"$i" "${a[i%4]}"
sleep 1
done
echo
My mistake. The for loop which has three arguments is exiting instead of the if condition failing.

conditional execution of steps after called function in bash

Requirement: Based upon IF condition in the called function: myfunc, echo hello in the for loop should not get executed and control should go to the next iteration.
In the below script, when the value of k becomes 2 and 3, echo hello should not get executed.
This is the script that I am trying to develop but no success.
#!/usr/bin/env bash
myfunc() {
if [[ $k -gt 1 ]]; then
echo "in the loop"
return
else
echo continue
fi
}
for (( k=1; k<=3; k++ ))
do
myfunc
echo hello
done
Please help.
Your loop is all wrong and I don't know why you have an if / else if you're just interested in one output:
#!/usr/bin/env bash
myfunc() {
if [[ $k -lt 2 ]]; then
echo "hello my value is $k"
fi
}
for (( k=1; k<=3; k++ ))
do
myfunc
echo "$k just to prove it is looping" # this is always run regardless of what's in the function
done
output:
hello my value is 1
1 just to prove it is looping
2 just to prove it is looping
3 just to prove it is looping
#!/usr/bin/env bash
myfunc() {
if [[ $k -gt 1 ]]; then
echo "in the loop"
x=1
else
echo Welcome
fi
}
for (( k=1; k<=3; k++ ))
do
myfunc
if [[ $x -eq 1 ]];then
continue
fi
echo hello
done

Limit bash until loop to 3 retries [duplicate]

How can this while loop be limited to maximum 10 retries?
#!/bin/sh
while ! test -d /somemount/share/folder
do
echo "Waiting for mount /somemount/share/folder..."
sleep 1
done
Keep a counter:
#!/bin/sh
while ! test -d /somemount/share/folder
do
echo "Waiting for mount /somemount/share/folder..."
((c++)) && ((c==10)) && break
sleep 1
done
You can also use a for loop and exit it on success:
for try in {1..10} ; do
[[ -d /somemount/share/folder ]] && break
done
The problem (which exists in the other solutions, too) is that once the loop ends, you don't know how it ended - was the directory found, or was the counter exhausted?
I would comment but I do not have enough points for that. I want to contribute anyway.
So this makes it work even if the while loop is nested in another loop. before the break the c variable is being reset to zero.
credits to #anubhava who came up with the original solution.
#!/bin/sh
while ! test -d /somemount/share/folder
do
echo "Waiting for mount /somemount/share/folder..."
((c++)) && ((c==10)) && c=0 && break
sleep 1
done
You can use until (instead of "while ! ... break), with a counter limit:
COUNT=0
ATTEMPTS=10
until [[ -d /somemount/share/folder ]] || [[ $COUNT -eq $ATTEMPTS ]]; do
echo -e "$(( COUNT++ ))... \c"
sleep 1
done
[[ $COUNT -eq $ATTEMPTS ]] && echo "Could not access mount" && (exit 1)
Notes:
Just like setting counter as variable, you can set var condition="[[ .. ]]", and use until eval $condition to make it more generic.
echo $(( COUNT++ )) increases the counter while printing.
If running inside a function, use "return 1" instead of "exit 1".

Counting down in a loop to zero by the number being given

I am trying to write a while loop to determine the number is being given to count down to 0. Also, if there's no argument given, must display "no parameters given.
Now I have it counting down but the last number is not being 0 and as it is counting down it starts with the number 1. I mush use a while loop.
My NEW SCRIPT.
if [ $# -eq "0" ] ;then
echo "No paramters given"
else
echo $#
fi
COUNT=$1
while [ $COUNT -gt 0 ] ;do
echo $COUNT
let COUNT=COUNT-1
done
echo Finished!
This is what outputs for me.
sh countdown.sh 5
1
5
4
3
2
1
Finished!
I need it to reach to 0
#Slizzered has already spotted your problem in a comment:
You need operator -ge (greater than or equal) rather than -gt (greater than) in order to count down to 0.
As for why 1 is printed first: that's simply due to the echo $# statement before the while loop.
If you're using bash, you could also consider simplifying your code with this idiomatic reformulation:
#!/usr/bin/env bash
# Count is passed as the 1st argument.
# Abort with error message, if not given.
count=${1?No parameters given}
# Count down to 0 using a C-style arithmetic expression inside `((...))`.
# Note: Increment the count first so as to simplify the `while` loop.
(( ++count ))
while (( --count >= 0 )); do
echo $count
done
echo 'Finished!'
${1?No parameters given} is an instance of shell parameter expansion
bash shell arithmetic is documented here.
You should also validate the variable before using it in an arithmetic context. Otherwise, a user can construct an argument that will cause the script to run in an infinite loop or hit the recursion limit and segfault.
Also, don't use uppercase variable names since you risk overriding special shell variables and environment variables. And don't use [ in bash; prefer the superior [[ and (( constructs.
#!/usr/bin/env bash
shopt -s extglob # enables extended globs
if (( $# != 1 )); then
printf >&2 'Missing argument\n'
exit 1
elif [[ $1 != +([0-9]) ]]; then
printf >&2 'Not an acceptable number\n'
exit 2
fi
for (( i = $1; i >= 0; i-- )); do
printf '%d\n' "$i"
done
# or if you insist on using while
#i=$1
#while (( i >= 0 )); do
# printf '%d\n' "$((i--))"
#done
Your code is far from being able to run. So, I don't know where to start to explain. Let's take this small script:
#!/bin/sh
die() {
echo $1 >&2
exit 1;
}
test -z "$1" && die "no parameters given"
for i in $(seq $1 -1 0); do
echo "$i"
done
The main part is the routine seq which does what you need: counting from start value to end value (with increment in between). The start value is $1, the parameter to our script, the increment is -1.
The test line tests whether there is a parameter on the command line - if not, the script ends via the subroutine die.
Hth.
There are a number of ways to do this, but the general approach is to loop from the number given to an ending number decrementing the loop count with each iteration. A C-style for loop works as well as anything. You will adjust the sleep value to get the timing you like. You should also validate the required number and type of input your script takes. One such approach would be:
#!/bin/bash
[ -n "$1" ] || {
printf " error: insufficient input. usage: %s number (for countdown)\n" "${0//*\//}"
exit 1
}
[ "$1" -eq "$1" >/dev/null 2>&1 ] || {
printf " error: invalid input. number '%s' is not an integer\n" "$1"
exit 1
}
declare -i cnt=$(($1))
printf "\nLaunch will occur in:\n\n"
for ((i = cnt; i > 0; i--)); do
printf " %2s\n" "$i"
sleep .5
done
printf "\nFinished -- blastoff!\n\n"
exit 0
Output
$ bash ./scr/tmp/stack/countdown.sh 10
Launch will occur in:
10
9
8
7
6
5
4
3
2
1
Finished -- blastoff!
Your Approach
Your approach is fine, but you need to use the value of COUNT $COUNT in your expression. You also should declare -i COUNT=$1 to tell the shell to treat it as an integer:
#!/bin/bash
if [ $# -eq "0" ] ;then
echo "No paramters given"
else
echo -e "\nNumber of arguments: $#\n\n"
fi
declare -i COUNT=$1
while [ $COUNT -gt 0 ] ;do
echo $COUNT
let COUNT=$COUNT-1
done
echo -e "\nFinished!\n"

Limit bash while loop to 10 retries

How can this while loop be limited to maximum 10 retries?
#!/bin/sh
while ! test -d /somemount/share/folder
do
echo "Waiting for mount /somemount/share/folder..."
sleep 1
done
Keep a counter:
#!/bin/sh
while ! test -d /somemount/share/folder
do
echo "Waiting for mount /somemount/share/folder..."
((c++)) && ((c==10)) && break
sleep 1
done
You can also use a for loop and exit it on success:
for try in {1..10} ; do
[[ -d /somemount/share/folder ]] && break
done
The problem (which exists in the other solutions, too) is that once the loop ends, you don't know how it ended - was the directory found, or was the counter exhausted?
I would comment but I do not have enough points for that. I want to contribute anyway.
So this makes it work even if the while loop is nested in another loop. before the break the c variable is being reset to zero.
credits to #anubhava who came up with the original solution.
#!/bin/sh
while ! test -d /somemount/share/folder
do
echo "Waiting for mount /somemount/share/folder..."
((c++)) && ((c==10)) && c=0 && break
sleep 1
done
You can use until (instead of "while ! ... break), with a counter limit:
COUNT=0
ATTEMPTS=10
until [[ -d /somemount/share/folder ]] || [[ $COUNT -eq $ATTEMPTS ]]; do
echo -e "$(( COUNT++ ))... \c"
sleep 1
done
[[ $COUNT -eq $ATTEMPTS ]] && echo "Could not access mount" && (exit 1)
Notes:
Just like setting counter as variable, you can set var condition="[[ .. ]]", and use until eval $condition to make it more generic.
echo $(( COUNT++ )) increases the counter while printing.
If running inside a function, use "return 1" instead of "exit 1".

Resources