Bash while loop till EOF - bash

I need to write a program that calculates the arithmetic mean and variance with intiger division, but i don't now how many numbers will be entered. Example input:
5
4
1
5
2
6
Example output:
3
8
For now when i enter x instead of a number, the loop ends, but those numbers are read from file, so i think it should be something like:
while read -r num; do
if [[ "$num" -eq EOF ]]; then #that condition is my question, what should be inside [[]]?
break
fi
else
#do sth
done
#the rest of the program

You don't get a special value when the end of the input file is reached; rather, read exits with a non-zero exit status, which terminates the loop. For example:
count=0
total=0
while read -r num; do
count=$((count + 1))
total=$((total + num))
done
avg=$((total / count))

Related

How do I write a Bash script for a C program that takes 4 numerical inputs? [duplicate]

This question already has answers here:
How to zero pad a sequence of integers in bash so that all have the same width?
(15 answers)
Closed 2 years ago.
I am writing a bash script for a c program, where the program asks for a 4 numerical pin inputs. However, when I wrote the script, the output seems to run in a loop, but it doesn't break where it gets identified as the correct number the program will accept.
#!/bin/bash
RANGE=9000
count=${RANDOM:0:4}
while [[ "$count" -le $RANGE ]]
do
number=$RANDOM
(( "number %= $RANGE" ))
echo $number
if [[ "$count" == "$RANGE" ]]; then
break
fi
done
When I run it, I can see some numbers in the output that returned as 2 or 3 digits, instead of 4. So in theory, what I want to do is find a random number that is 4 digits that the program will take, but I don't know what is the random number, so essentially it is a brute force, or just me manually guessing the pin number.
If all you need is a random 4-digit number, you can do that with:
printf -v number "%04d" $((RANDOM % 10000))
The $RANDOM gives you a random number 0..32767, the % 10000 translates that to the range 0..9999 (not perfectly distributed, but should be good enough for most purposes), and the printf ensures leading zeros are attached to it (so you'll see 0042 rather than 42, for example).
You can test it with the following script:
(( total = 0 ))
(( bad = 0 ))
for i in {1..10000} ; do
printf -v x "%04d" $((RANDOM % 10000))
(( total += 1 ))
[[ "${x}" =~ ^[0-9]{4}$ ]] || { echo Bad ${x}; (( bad += 1 )); }
done
(( good = total - bad ))
echo "Tested: ${total}, bad ${bad}, good ${good}"
which should give you:
Tested: 10000, bad 0, good 10000

bash - while loop - rolling 2 dice

I'm writing a bash script that rolls 2 dice(with 6 sides). When the 2 dice hits double sixes I want the script to stop (break) and count how many rolls it took to get double sixes.
#!/bin/bash
DOUBLESIX="6-6"
while (( 0 ==0 )) ; do
dice=$RANDOM; ((dice = dice % 6 )); (( dice = dice +1 ))
dice2=$RANDOM; ((dice2 = dice2 % 6 )); (( dice = dice + 1))
pair="$dice-dice$2"
echo $pair
if [[ "$pair" == "$DOUBLESIX" ]]; then
break
fi
done
echo "It took $count rolls to get 6-6 "
Here's what i have so far. Question is, how do I count how many times the while loop ran and put it in my $count?
Thanks in advance!
I won't comment too much on the other potential issues you have with your code, such as the dice$2 "variable", or the fact you can generate a random number between one and six inclusive with the somewhat simpler ((num = $RANDOM % 6 + 1)) - the learning process of fixing/improving those is what will make you a better coder.
But, for the specific question on how to maintain a count, that's relatively simple. Before the loop starts, insert the following code to initialise the count to zero:
((count = 0))
Then, with each roll of the two dice, use the following to increment the count:
((count = count + 1))
An example of how to do this can be seen below. It's for counting from one to ten but you should get the idea:
((count = 1))
while [[ ${count} -le 10 ]] ; do
echo $count
((count = count + 1))
done
For what it's worth (don't use this if this is a classwork problem, you'd be crazy to think educators don't search the net for plagiarism), here's how I would implement such a beast:
#!/bin/bash
DESIRED="6-6"
((count = 0))
dice="NOT ${DESIRED}"
while [[ "${dice}" != "${DESIRED}" ]] ; do
((count = count + 1))
((die1 = $RANDOM % 6 + 1))
((die2 = $RANDOM % 6 + 1))
dice="${die1}-${die2}"
echo ${dice}
done
echo "It took ${count} rolls to get ${DESIRED}"
I advice to use shuf for this purpose.
#!/bin/bash
declare -i count=1
while [ "6 6" != "$(shuf --input-range='1-6' -r -n 2 | xargs)" ]; do
(( ++count ))
done
echo "It took $count rolls to get double six."
To generating two random numbers between 1 and 6 we use
shuf --input-range='1-6' -r -n 2
shuf [OPTION]... [FILE] write a random permutation of the input lines to standard output. Each output permutation is equally likely. -i lo-hi or --input-range=lo-hi act as if input came from a file containing the range of unsigned decimal integers lo-hi, one per line. -r or --repeat repeat output values, that is, select with replacement. With this option the output is not a permutation of the input; instead, each output line is randomly chosen from all the inputs. -n count or --head-count=count output at most count lines (by default, all input lines are output). If --head-count is not given, shuf repeats indefinitely.
Type man shuf or see coreutils manual for more details.

Bash Script accepting a number, then printing a set of int from 0 to the number entered

I am trying to write a bash script that accepts a number from the keyboard, and then prints a set of integers from 0 to the number entered. I can't figure out how to do it at all.
This is my code:
while [ 1 ]
do
echo -n "Enter a color: "
read user_answer
for (( $user_answer = $user_answer; $user_answer>0; $user_answer--))
echo $user_answer
fi
done
exit
The error I'm recieving is:
number_loop: line 10: syntax error near unexpected token echo'
number_loop: line 10: echo $user_answer'
Assign a separate variable in order to use increment/decrement operators. $user_answer=$user_answer will always be true and it will throw an error when trying to use decrement. Try the following :
#!/bin/bash
while [ 1 ]
do
echo -n "Enter a color: "
read user_answer
for (( i=$user_answer; i>0; i-- ))
do
echo $i
done
done
exit
You missed the do statement between your for and the echo.
bash has many options to write numbers. What you seem to be trying to do is easiest done with seq:
seq $user_answer -1 0
If you want to use your loop, you have to insert a ; do and replace the fi with done, and replace several $user_answer:
for (( i = $user_answer; i>0; i--)); do
echo $i
done
(btw: I assumed that you wanted to write the numbers in reverse order, as you are going backwards in your loop. Forwards is even easier with seq:
seq 0 $user_input
)
This is where a c-style loop works particularly well:
#!/bin/bash
for ((i = 1; i <= $1; i++)); do
printf "%s\n" "$i"
done
exit 0
Example
$ bash simplefor.sh 10
1
2
3
4
5
6
7
8
9
10
Note: <= is used as the for loop test so it 10 it iterates 1-10 instead of 0-9.
In your particular case, iterating from $user_answer you would want:
for (( i = $user_answer; i > 0; i--)); do
echo $i
done
The for loop is a bash internal command, so it doesn't fork a new process.
The seq command has a nice, one-line syntax.
To get the best of the twos, you can use the { .. } syntax:
eval echo {1..$answer}

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

For loop in shell script with integer as input

I am trying to take integer as a input and trying to print numbers from 1 to the input number.
How can I do that?
Something like this will work:
read -p "Loop until: " n
for i in $(seq 1 $n); do
echo $i;
done
$n will contain the user input.
The seq program simply builds a sequence of numbers from 1 to $n, and the for loop prints every item in this sequence.
Instead of using seq command you can use the arithmetic initialisation in a shell.
You can use the following code to do it.
$ cat test
#!/bin/bash
read -p "Loop until: " n
a=1
while true; do
if [ $a -le $n ]; then
echo $a
else
break
fi
a=$(($a+1))
done
$ sh test
Loop until: 4
1
2
3
4

Resources