Count down with until - bash

I get the issue when I give the user an option to enter a number, that number is going to be counted down to 1. I'm lost after the echo line, as the script echos the value entered but doesn't count it down to 1.
#!/bin/bash
COUNTER=100
until [ $COUNTER -lt 1 ]; do
read -p "Enter a number between 1-100: " COUNTER
echo COUNTER $COUNTER
let COUNTER-=1
done

Move the read out of the loop like this:
read -p "Enter a number between 1-100: " COUNTER
until [ $COUNTER -lt 1 ]; do
echo COUNTER $COUNTER
let COUNTER-=1
done

Try doing this using modern bash :
#!/bin/bash
read -p "Enter a number between 1-100: " counter
until ((counter < 1)); do
echo "counter $counter"
((counter--))
done
put read outside of the for loop to do it successfully.
avoid using UPPER CASE variables by default, there's reserved for global system variables.
((...)) is more intuitive than -gt, -lt... and is an arithmetic command, which returns an exit status of 0 if the expression is nonzero, or 1 if the expression is zero. Also used as a synonym for "let", if side effects (assignments) are needed. See http://mywiki.wooledge.org/ArithmeticExpression

Related

what code function will help to ask for input when i try to execute a code with no previous value in shell script

When I choose Option 3 after opening the file it just terminates.
I was trying to use if else function inside section 3 where it ask for new values if there is none stored so that instead of terminating it will ask for values but cant seem to work it out.
#!/bin/bash
while : #This program demonstrate 4 option below
do
clear
echo "Main Menu"
echo "Select any option of your choice"
echo "[1] Show Todays date/time,Files in current directory,home
directory,user id "
echo "[2] Enter a range "
echo "[3] Highest and lowest of the eight random numbers "
echo "[4] Exit/Stop "
echo "==========="
echo -n "Menu choice [1-4]: "
read -r yourch #Choose option out of 4
case $yourch in
1) echo "Today is";date;
echo "Your home directory is:";home;
echo "Your path is :";PWD;
echo "Current Shell";uname;
echo "Your Student ID $USER ID ";
echo "Press a key...";read -r;;
2) echo "Lower value" #Enter the lower value
read -r s1
echo "Higher value" #Enter the higher value
read -r s2
dif=$((s2-s1))
if [ $dif -ne 100 ]
then
echo "Range should be 100"
else #if the differnce is 100 then programe run otherwise terminates
in=$( ("$s2" - "$s1")) #formula for the range
echo "8 random numbers between $s1 and $s2 are :-"
for i in $(seq 1 8)
do
t=$( ($RANDOM % "$in"))
n=$( ("$t" + "$s1"))
echo "$n" #Here we get the random numbers
done
fi
echo "Press a key..."; read -r;;
3) diff=$((s2 - s1)) #Depicts Highest and lowest numbers of the randoms
RANDOM=$$
min=9999
max=-1
for i in $(seq 8)
do
R=$((((RANDOM%diff))+s1))
if [[ "$R" -gt "$max" ]]
then
max=$R
fi
if [[ "$R" -lt "$min" ]]
then
min=$R
fi
done
echo "Biggest number and smallest numbers are $max and $min" #Prints the highest and lowest numbers
echo "press a key...";read -r;;
4)echo " THANK YOU VERY MUCH $ Good Bye"
exit 0;; #Exit command
*)echo "Opps!!! Please select choice 1,2,3,4";
echo "press a key...";read -r;;
esac
done
I would like for it to ask for new values if there is no previous data stored.
I checked your script, to see the problem. It terminates with a division by zero, because s1 and s2 initially are not set. To resolve this, you can use code like
if [ -z "${s1}" ] ;then
read -p "s1 is empty, please enter a number " s1
fi
if [ -z "${s2}" ] ;then
read -p "s2 is empty, please enter a number " s2
fi
-z "..." is true, if the string is empty. The shell doesn't distinguish data types and because I use the doublequotes it is safe to check for an empty string because if s1 is not set, "$s1" results in an empty string.
Btw. "$s1" is logically equivalent to "${s1}", but it is safer to use the curly braces, because there are no ambiguities this way where the variable ends. For example consider the lines:
year=90
echo "I like the music of the $years"
#
echo "I like the music of the ${year}s"
The first echo outputs "I like the music of the" unless variable "years" was set before, while the second outputs "I like the music of the 90s". Without curly braces this would be a bit more inconvenient. Without curly braces sometimes you might run in such ambiguities, without recognizing it easily.

Unix Scripting - Finding Minimum and Maximum (Bash Shell)

My code below is part of an assignment, but I'm racking my head against the desk not understanding why it won't assign a "MIN" value. I tried assigning the MIN and MAX to ${LIST[0]} just to have the first index in place, but it returns the whole array, which doesn't make sense to me. I'm executing this on a CentOS VM (which I can't see making a difference). I know the beginning of the first and second "if" statements need better logic, but I'm more concerned on the MIN and MAX outputs.
#!/bin/bash
LIST=()
read -p "Enter a set of numbers. " LIST
MIN=
MAX=
if [ ${#LIST[*]} == 0 ]; then echo "More numbers are needed."; fi
if [ ${#LIST[#]} -gt 0 ]; then
for i in ${LIST[#]}; do
if [[ $i -gt $MAX ]]; then
MAX=$i
fi
if [[ $i -lt $MIN ]]; then
MIN=$i
fi
done
echo Max is: $MAX.
echo Min is: $MIN.
fi
The code is almost functional.
Since $LIST is an array, not a variable, change read -p "Enter a set of numbers. " LIST to:
read -p "Enter a set of numbers. " -a LIST
Move the $MIN and $MAX init code down 5 lines, (just before the for loop):
MIN=
MAX=
...and change it to:
MIN=${LIST[0]}
MAX=$MIN
And it'll work. Test:
echo 3 5 6 | ./minmax.sh
Output:
Max is: 6.
Min is: 3.

bash - how to put $RANDOM into value?

newbie to bash:
basically I want to compare the result of $RANDOM to another value which is given by the user through 'read'
code for more info:
echo $RANDOM % 10 + 1 | bc
basically I want an if statement as well to see if the result of that $RANDOM value is equal to something that the user typed in e.g.:
if [ [$RANDOM VALUE] is same as $readinput
#readinput is the thing that was typed before
then
echo "well done you guessed it"
fi
something along the lines of that!!
to summarise
how do i make it so that i can compare a read input value to echo "$RANDOM % 10 + 1 | bc"
think of the program I am making as 'GUESS THE NUMBER!'
all help VERY MUCH APPRECIATED :)
There's no need for bc here -- since you're dealing in integers, native math will do.
printf 'Guess a number: '; read readinput
target=$(( (RANDOM % 10) + 1 )) ## or, less efficiently, target=$(bc <<<"$RANDOM % 10 + 1")
if [ "$readinput" = "$target" ]; then
echo "You correctly guessed $target"
else
echo "Sorry -- you guessed $readinput, but the real value is $target"
fi
The important thing, though, is the test command -- also named [.
test "$readinput" = "$target"
...is exactly the same as...
[ "$readinput" = "$target" ]
...which does the work of comparing two values and exiting with an exit status of 0 (which if will treat as true) should they match, or a nonzero exit status (which if will treat as false) otherwise.
The short answer is to use command substitution to store your randomly generated value, then ask the user for a guess, then compare the two. Here's a very simple example:
#/bin/bash
#Store the random number for comparison later using command substitution IE: $(command) or `command`
random=$(echo "$RANDOM % 10 + 1" | bc)
#Ask the user for their guess and store in variable user_guess
read -r -p "Enter your guess: " user_guess
#Compare the two numbers
if [ "$random" -eq "$user_guess" ]; then
echo "well done you guessed it"
else
echo "sorry, try again"
fi
Perhaps a more robust guessing program would be embedded in a loop so that it would keep asking the user until they got the correct answer. Also you should probably check that the user entered a whole number.
#!/bin/bash
keep_guessing=1
while [ "$keep_guessing" -eq 1 ]; do
#Ask the user for their guess and check that it is a whole number, if not start the loop over.
read -r -p "Enter your guess: " user_guess
[[ ! $user_guess =~ ^[0-9]+$ ]] && { echo "Please enter a number"; continue; }
#Store the random number for comparison later
random=$(echo "$RANDOM % 10 + 1" | bc)
#Compare the two numbers
if [ "$random" -eq "$user_guess" ]; then
echo "well done you guessed it"
keep_guessing=0
else
echo "sorry, try again"
fi
done

Why is this bash program going into an infinite loop?

#!/bin/bash
echo "Enter number of loops"
read count
echo $count
if [ $count -eq 0 ]
then
echo "The count cannot be zero. Enter a number again"
read count
fi
while [ $count -gt 0 ]
do
echo "Loop numner $count"
count = `expr $count - 1`
done
I am trying to simulate a Java counter in bash. Does this exist?
You have space in between your assignment statement as below:
count = `expr $count - 1`
^ ^
Remove the space between "=" like below:
count=`expr $count - 1`
Output
Enter number of loops
10
10
Loop numner 10
Loop numner 9
Loop numner 8
Loop numner 7
Loop numner 6
Loop numner 5
Loop numner 4
Loop numner 3
Loop numner 2
Loop numner 1
Note apart, backticks are discouraged and you should be using something like:
count=$(expr $count - 1)
Here's a rock solid rewriting of your script, to show you how it's usually done:
#!/bin/bash
while true; do
read -rep "Enter number of loops: " count
if [[ $count = +([[:digit:]]) ]]; then
((count=10#$count))
((count>0)) && break
printf 'The count cannot be zero. Enter a number again.\n'
else
printf 'Please enter a valid number.\n'
fi
done
while ((count>0)); do
printf 'Loop number %s\n' "$count"
((--count))
done
Using read with the -r flag to have backslashes not escape some characters (this should be the default), with the -e option so that read uses readline: it's more comfortable for the user, and with the -p option to specify the prompt.
I completely revisited the logic you're using to read user's input: read is run in an infinite loop that can only be broken when user enters a valid number. With your method, a user could enter invalid data twice, and the loop would have run with random arguments. Not good.
To check that user input is valid, I'm using pattern matching: [[ $count = +([[:digit:]]) ]] that is true if and only if count expands to a string of one or more digits, then I'm making sure that Bash will treat count in radix 10: in arithmetic context, 10#$count treats count in radix 10. Without this, an input like 08 or 09 would make some subsequent parts fail, as a leading zero means, for Bash, that the number should be interpreted in radix 8, hence 08 is not valid!
The final loop is written with Bash's arithmetic context ((...)). You don't need the external expr to perform simple arithmetic.
You can also use bash arithmetic expansion:
count="$((count -1))"
I would also suggest making the first test -le not -eq, in case the user types in a negative integer, and quote it in case the user types nothing at all.
if [ "$count" -le 0 ]
So your code would be:
#!/bin/bash
echo "Enter number of loops"
read count
echo $count
if [ "$count" -le 0 ]
then
echo "The count cannot be zero. Enter a number again"
read count
fi
while [ $count -gt 0 ]
do
echo "Loop numner $count"
count="$((count - 1))"
done

Shell script I am trying to get the product of odd numbers

mul=1
i=0
while [ $i -ne 10 ]
do
echo "Enter Number"
read num
if [ `expr $num % 2` -ne 0 ]
then
mul=`expr $mul*$num`
fi
i=`expr $i + 1`
done
echo mul of odd numbers = $mul
this is what i tried...its showing output as 1*3*5*7*9
pls correct the error here
Thanks in advance
"*" has a special meaning, hence you need to escape it and need to have a space between the two variables like:
mul=`expr $mul \* $num`
Note aside- Use of back ticks are discouraged and you may want to use something instead like:
mul=$(expr $mul \* $num)
Since your don't provide some details (see my comment above) I can't guarantee this answers your question and produces the desired result. This assumes your shell is bash. Please inform me and I'll edit the answer accordingly.
Consider the changes below. The relevant part is the change from expr ... to $(( ... )), which is bash's built-in arithmetic expression evaluator.
#!env bash
MUL=1
I=0
while [ $I -ne 10 ]
do
echo "Enter Number"
read NUM
if [[ $(($NUM % 2)) -ne 0 ]] ; then
MUL=$(($MUL * $NUM))
fi
I=$(($I + 1))
done
echo MUL of odd numbers = $MUL
This produces the following output:
$ sh foo.sh
Enter Number
1
Enter Number
2
Enter Number
3
Enter Number
4
Enter Number
5
Enter Number
6
Enter Number
7
Enter Number
8
Enter Number
9
Enter Number
0
MUL of odd numbers = 945

Resources