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

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

Related

Bash script For Cycle

i´m new to scripting and bash.
I need help with bash script (for cycle)
I´ve got a script called for.sh
It has to ask 10 numbers from user with for cycle.
In every cycle number will be divided with 3 or 5.
If it divides it will say it.
My idea was to use read, for i in $(eval echo "$numbers") and if commands but that does not seem to work.
This can be achieved by for as well as while loop.
using for loop here:
#!/bin/bash
for (( i=1; i<=10; i++ ))
do
read -p "Enter the number:" num
if [[ $(($num%3)) -eq '0' ]]
then
echo "$num is divisible by 3"
elif [[ $(($num%5)) -eq '0' ]]
then
echo "$num is divisible by 5"
else
echo "$num is not divisible by either 3 or 5"
fi
done
I've initialized a variable i to 1, so everytime the for loop will run ,it'll ask the number from the user, store it into another variable called num and then check if the entered number is divisible by 3 or 5, if the entered number is not divisible by 3 or 5, it will say "number is not divisible by either 3 or 5".
With every run, the for loop will increment the count by 1 till it reaches the count=10.

Formatting Output From Shell Script [duplicate]

This question already has answers here:
Echo tab characters in bash script
(10 answers)
Closed 5 years ago.
I am working on a shell script that takes stdin or file as input and prints the averages and medians for rows or columns depending on the arguments.
When calculating the averages for the columns, the output needs to print out the following (tabbed):
My output currently looks like this (no spaces or tabs):
Averages:
92480654263
Medians:
6368974
Is there a way to echo out the averages and medians with tabs so each average and median set align left correctly? Here is a sample of how I am printing out the averages:
echo "Averages:"
while read i
do
sum=0
count=0
mean=0
#Cycle through the numbers in the rows
for num in $i
do
#Perform calculations necessary to determine the average and median
sum=$(($sum + $num))
count=`expr $count + 1`
mean=`expr $sum / $count`
done
echo -n "$mean"
done < $1
man echo:
-e enable interpretation of backslash escapes
If -e is in effect, the following sequences are recognized:
\t horizontal tab
I'd try echo -n -e "$mean\t", didn't test it though.
You should use printf. For instance, this will print a value followed by a tab
printf "%s\t" "$mean"
You can actually print several values separated by tabs if you want by adding arguments :
printf "%s\t" "$mean" "$count"
You can use an array expansion to print several values separated by tabs :
printf "%s\t" "${my_array[#]}"
Among advantages of printf over echo is the availability of flexible formatting strings, and the fact that implementations of printf vary less than those of echo among shells and operating systems.
You could try using column command but it does take additional steps:
echo "Averages:"
while read line
do
sum=0
count=0
mean=0
#Cycle through the numbers in the rows
for num in $line
do
#Perform calculations necessary to determine the average and median
(( sum += num ))
(( count++ ))
(( mean = sum / count ))
done
(( mean == 0 )) && out=$mean || out="$out|$mean"
done < $1
echo "$out" | column -s'|' -t
Above is untested as I do not have the original file, but you should get the idea. I would add that the division will also provide truncated values so not exactly accurate.

Recursive calls in bash (catalan-numbers)

Im trying to create a program that lists all catalan-numbers below or equal to an argument in a bash-script. This is what I currently have but its giving me a stackoverflow error (I believe the error must be in the for-loop, but I can't figure out why). I have made this program in java and it works so I think it must be some syntax error?
#!/usr/bin/env bash
pcat=0
Cat() {
res=0
if [ $1 -le 1 ]
then
echo 1
return 1
fi
for ((i=0; i<$1; i++))
do
var1=$(($1-($i+1)))
call1=$(Cat $i)
call2=$(Cat $var1)
res=$(( res+call1+call2 ))
done
echo ${res}
return res
}
while [ $pcat -lt $1 ]
do
Cat $pcat
pcat=$((pcat+1))
done
The line where you do return res is incorrect, return could deal only with numbers and number less than 128 in general.
Assuming what you meant was return $res, the script will run.
I managed to get the program working with a similar code to yours:
#!/bin/bash
catalan() {
local n=$1
#echo "called with $n" >&2
if (( n <= 1 )); then
res=1
else
res=0
for ((i=0; i<n; i++))
do
var1=$(( n-i-1 ))
call1=$(catalan $i)
call2=$(catalan $var1)
res=$(( res+call1*call2 ));
#echo ":$i:$var1: result Call1:$call1: and Call2:$call2: $res" >&2
done
fi
#echo "result is ${res}" >&2
echo "$res"
}
n=$1
until (( pcat > n ))
do catalan "$((pcat++))"
done
echo "all was done"
There was a second problem in that the values of Call1 and Call2 need to be multiplied, not added. Changed res+call1+call2 to:
res=$(( res+call1*call2 ))
But the resultant code was very slow. Just to calculate the tenth (10) catalan number the code took 16 seconds.
An entirely new program that keeps the values inside a single array: catarray.
As this:
#!/bin/bash
# some initial values to jump start the code:
catarray=( 1 1 2 5 )
#############################################################################
catalan(){
#echo "making call for $1" >&2
local n=$1
# ${#catarray[#]} is the count of values in catarray (last index + 1).
# if the number n to be found is not yet in the array of values of
# catarray then we need to calculate it. Else, we just print the value.
if (( n >= ${#catarray[#]} )); then
#echo "$n is bigger than ${#catarray[#]}" >&2
# this is a new number, lets loop up till we
# fill the array just up to this value
for (( i=${#catarray[#]};i<=n;i++)); do
#echo "fill index $i in array" >&2
# calculate the sum of all terms for catalan of $n.
for(( j=0;j<i;j++ )); do
(( catarray[i] += catarray[j] * catarray[i-j-1] ))
#echo "done math in $i for $j with ${catarray[j]} *
#echo "* ${catarray[i-j-1]} = ${catarray[i]}"
done
done
fi
# After making the math or else we just print the known value.
#printf 'result of catalan number is %s\n' "${catarray[n]}"
}
#############################################################################
catalan "$1"
printf '%s, ' "${catarray[#]}"; echo
Wich will execute the tenth (10) catalan number in just 4 milliseconds.
A lot of echos were included to "see" how the program works. You may unquote them.
There is a limit though, numbers in bash should fit in 64 bits (for 64 bit computers) or be less than (2^63-1). That makes the biggest catalan number possible the 35th.
$ catalan 35
1, 1, 2, 5, 14, 42, 132, 429, 1430, 4862, 16796, 58786, 208012, 742900,
2674440, 9694845, 35357670, 129644790, 477638700, 1767263190,
6564120420, 24466267020, 91482563640, 343059613650, 1289904147324,
4861946401452, 18367353072152, 69533550916004, 263747951750360,
1002242216651368, 3814986502092304, 14544636039226909,
55534064877048198, 212336130412243110, 812944042149730764,
3116285494907301262
But will only take ~20 miliseconds to do that.

if else dividing in BASH [duplicate]

This question already has answers here:
Arithmetic expressions in Bash?
(5 answers)
Closed 6 years ago.
I am doing a school assignment in bash and got this code:
if a < 0
a = a/b
else
a = b/a
fi
The assignment says that we need to divide two number read from the keyboard, and check if the first number is larger than the number 0.
echo "Write two numbers, with a space, that need to be divided:"
read a b
if a > 0
a = $a / $b
else
a = $b / $a
fi
echo "$a"
What am I doing wrong here?
Creating a math context in bash uses (( )). Note that bash only supports integer math natively -- be sure you aren't expecting fractional output (or using fractional inputs), and see BashFAQ #22 if this limitation is relevant to you.
if (( a > 0 )); then
a=$(( a / b ))
else
a=$(( b / a ))
fi

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.

Resources