bash - how to put $RANDOM into value? - bash

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

Related

How to use a for loop to create folders in bash

I want to create a directory in which there is a bunch of text files using a for loop. Here is my code:
#!/bin/bash
echo "enter the nums: "
read num1 num2
for (( counter=0; counter<$num2; counter++ ))
do
if [ $num1 -lt 10 ] && [ $num2 -lt 10 ];
then
mkdir $num1 && touch $num1/$num1$num2.txt
echo "$num1""$num2" > $num1/$num1$num2.txt
else
echo "you weren't supposed to do that"
fi
done
What I want to happen if for example the user entered: "2 9"
Make a directory called 2
In it make text files called 290.txt, 291.txt, 292.txt... up till 299.txt.
Instead, what happens right now is it makes the directory and gives an error that the directory already exists. I don't know the next step, please help.
The biggest problem here is that you're doing things inside the loop that really only should be done once. Specifically, the error you're getting is because it tries to create the directory every time through the loop, but you can only create it once. Also, if the user enters too large a number, it'll print multiple error messages (e.g. if num2 is entered as 500, it'll print 500 error messages). You need to do both the error check and creating the directory once, before the loop.
A second problem is that you don't add $counter to the filename, so if the user enters "2 9", it'll create a file named 29.txt nine times.
You also have some more minor issues: in general, error messages should be printed to standard error instead of standard output (you can redirect them with >&2), and if there's an error the script should exit with a nonzero status. Also, you should (almost always) put double-quotes around variable references, to avoid weird results if the variables are blank or contain whitespace or some other things. You also don't need to touch files before writing into them (using > somefile will create the file if it doesn't exist).
With these things fixed (and some stylistic tweaks), here's what I get:
#!/bin/bash
echo "enter the nums: "
read num1 num2
if ! [ "$num1" -lt 10 ] || ! [ "$num2" -lt 10 ]; then
echo "you weren't supposed to do that" >&2 # message send to stderr
exit 1 # exit with error status
fi
mkdir "$num1" || exit $? # if mkdir fails, exit with its error status
for (( counter=0; counter<$num2; counter++ )); do
echo "${num1}${num2}" > "${num1}/${num1}${num2}${counter}.txt"
done
BTW, the ! [ "$num1" -lt 10 ] tests may look a little weird; why not just use [ "$num" -ge 10 ]? I did it that way in case $num1 and/or $num2 isn't a valid number, in which case both -lt and -ge tests would fail; using a negated test makes that an error rather than a success.
I'm not fluent in bash or anything, but it looks like mkdir $num1 is called on every loop. Find out first if the directory exists.
Here you are! change the if and for statement parent and child:
#!/bin/bash
echo "enter the nums: "
read num1 num2
if [ $num1 -lt 10 ] && [ $num2 -lt 10 ]; then
mkdir $num1
for i in $(seq 0 $num2); do
touch $num1/$num1$num2$i.txt
echo "$num1""$num2""$i" > $num1/$num1$num2$i.txt
done
else
echo "you weren't supposed to do that"
fi

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 shell, Adding a variable number of variables

I am trying to write a short script that accepts a variable number of parameters (also numbers)
then adds those parameters together to get a total of the numbers. Then gets an average for those numbers entered.
This is what i have so far;
#!/bin/bash
count=1
ncount=1
echo
echo "please enter number of parameters: "
read parano
while [ $parano -ge $numbers$count ]
do
echo
echo "Please enter parameter $count: "
read number$ncount
let count=count+1
let ncount=ncount+1
done
Total=$((number$ncounttotal))
Average=$((Total/parano))
echo
echo "You have chosen $parano parameters"
echo
echo "The average is $Average"
echo
Its just the line for calculating the total that I am having issues with and cannot seem to find the code to calculate it. The rest seems to be working great but the average always comes out as 0 because of the total not being calculated.
Anyone have any ideas?
#!/bin/bash
[ $# -eq 0 ] && exit 1
for number in $#; do
sum=$(($sum + $number))
done
average=$(echo "$sum / $#" | bc -l)
echo $average
Then call it like:
./shellscript 1 2 3
I use bc above since bash will only do integer arithmetic and that's not great for the average.
Thank you for the help guys. The answer to what I needed was an array as mentioned.
#!/bin/bash
echo
echo "Please enter number of parameters: "
read parano
count=1
Total=$((0))
while [ $parano -ge $numbers$count ]
do
echo
echo "Please enter parameter $count: "
read number
let count=count+1
Total=$(($Total+number))
done
Average=$((Total/parano))
echo
echo "You have chosen $parano parameters"
echo
echo "The total is $Total "
echo
echo "The average is $Average"
echo
Answer was to make an array as the total and keep adding the variables to the array as they went along. At least that's what I think it is. Either way it works so thanks all!

bash, prompt for numerical input

d is an internal server lookup tool I use.
I am looking to allow a user to input any number between 0 (or 1) and 9999 (let's call this userinput) and have it display the result of:
d $userinput (e.g. 1234)
Then manipulate the results of that lookup (below gets rid of everything but the IP address to ping later):
grep -E -o '(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)'`
I know I need to use the while true; do read $blah etc etc. I am just not familiar with read enough to format it properly and more importantly:
get it to prompt for a numerical input between 0-9999
The other answers have many flaws, because they check that the user didn't input a number outside of the range they want. But what if a user enters something that is not a number? their strategy is broken from the start.
Instead it's better to let go only when we're sure that the user entered a number which lies within the wanted range.
while :; do
read -ep 'Enter server number: ' number
[[ $number =~ ^[[:digit:]]+$ ]] || continue
(( ( (number=(10#$number)) <= 9999 ) && number >= 0 )) || continue
# Here I'm sure that number is a valid number in the range 0..9999
# So let's break the infinite loop!
break
done
The regex [[ $number =~ ^[[:digit:]]+$ ]] makes sure that the user only entered digits.
The clumsy (number=(10#$number)) part is here so that if the user enters a number that starts with a 0, bash would try to interpret it in radix 8 and we'd get a wrong result (e.g., if the user enters 010) and even an error in the case when a user enters, e.g., 09 (try it without this guard).
If you only want to prompt once and exit when the user inputs invalid terms, you have the logic:
read -ep 'Enter server number: ' number
[[ $number =~ ^[[:digit:]]+$ ]] || exit 1
(( ( (number=(10#$number)) <= 9999 ) && number >= 0 )) || exit 1
# Here I'm sure that number is a valid number in the range 0..9999
If you want to explain to the user why the script exited, you can use a die function as:
die() {
(($#)) && printf >&2 '%s\n' "$#"
exit 1
}
read -ep 'Enter server number: ' number
[[ $number =~ ^[[:digit:]]+$ ]] ||
die '*** Error: you should have entered a number'
(( ( (number=(10#$number)) <= 9999 ) && number >= 0 )) ||
die '*** Error, number not in range 0..9999'
# Here I'm sure that number is a valid number in the range 0..9999
<--edit-->
if all you want is the mechanic for prompting, try this:
echo -n "Enter server number:"
read userinput
then run validation checks on the input like this:
if [[ $userinput -lt 0 || $userinput -gt 9999 ]] # checks that the input is within the desired range
then
echo "Input outside acceptable range."
else
# insert your grep and ping stuff here
fi
<--end edit-->
on first read, i thought your problem sounded ideal for a wrapper script, so i was going to suggest this:
$ cat wrapper.sh
#!/usr/bin/bash
userinput=$1
if [[ $# != 1 ]] # checks that number of inputs is exactly one
then
echo "Too many inputs."
exit 2
elif [[ $userinput -lt 0 || $userinput -gt 9999 ]] # checks that the input is within the desired range
then
echo "Input outside acceptable range."
exit 3
fi
output=`d "$userinput"`
ping_address=`grep -E -o '(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)' <("$output")`
ping "$ping_address"
then call the script with like this:
$ wrapper.sh 1243
If you just want a number between two values, you can test their values:
read x
while [[ $x -lt 0 || $x -gt 9999 ]]; do
echo "bad value for x"
read x
done
echo "x=$x"
The read command doesn't prompt itself. Use a normal echo before to actually display a prompt. Use echo -n to not add a newline.

Resources