Trying to write a script that accepts exactly one command line argument and must be a positive number. I have the one argument down, but can't figure out the positive number.
I have the following:
#!/bin/ksh
NUMBER=$1
# Accepts only one argument or does not execute.
if [ "$#" != 1 ]
then
echo "error: program must be executed with 1 argument."
exit
else
if [ "$#" < 1 ] # **NEED HELP HERE**. Check for negative number.
then
echo "error: argument must be a positive number."
fi
fi
do
echo -n $NUMBER
if [ $NUMBER -gt 1 ]
then
echo -n ", "
fi
NUMBER=$(($NUMBER - 1))
done
echo
...Need help with identifying if command line argument is a negative number.
Thanks
Verify it is a number using by checking the whether it is only digits:
#!/bin/ksh
NUMBER=$1
# Accepts only one argument or does not execute.
if [ "$#" != 1 ]
then
echo "error: program must be executed with 1 argument."
exit
else
case $NUMBER in
''|*[!0-9]*)
echo "error: argument must be a positive number."
exit
;;
esac
fi
while ! [ $NUMBER -lt 1 ]
do
echo -n $NUMBER
if [ $NUMBER -gt 1 ]
then
echo -n ", "
fi
NUMBER=$(($NUMBER - 1))
done
echo
Following will work:
test "$NUMBER" -ge 0 && printf "NOT NEGATIVE" || printf "NEGATIVE"
Assuming we're only talking about positive (base-10) integers ... and excluding commas, exponential notation and leading plus sign (+) ...
# test for ${NUMBER} containing anything other than digits 0-9
if [[ "${NUMBER}" = #(*[!0-9]*) ]]
then
echo "error: argument is not a positive number."
else
echo "success: argument is a positive number"
fi
Obviously it becomes a bit more interesting as you strip away the assumptions on what's defined as a *valid* positive number.
Expanding on the solution proposed by sqrt163 ... a simple function should allow us to handle exponential notation, float/real and numbers with a leading plus sign (+), while allowing the calling process to filter out messages about syntax errors ...
$cat test.sh
#!/bin/ksh
NUMBER=$1
isnumber()
{
# following should generate a non-zero for negative and non-numerics,
# while allowing the parent process to filter out syntax errors
[[ "${1}" -gt 0 ]]
}
# direct isnumber() output to /dev/null since we're only interested
# in the return code, and we want to mask any syntax issues if
# isnumber() is called with a non-numeric argument; unfortunately,
# for a valid numeric that contains a comma (eg, NUMBER = 1,000)
# our isnumber() call will fail
if isnumber ${NUMBER} >/dev/null 2>&1
then
echo "${NUMBER} is a positive number"
else
echo "${NUMBER} is not a positive number"
fi
And some tests ...
$ for s in 1 1.33 1e5 1e-4 +1 +1.65 +1e4 1,000 -1 -1.234 -1e5 -1,000 a b a1b ab1 1ab "a b c"
do
test.sh "$s"
done
1 is a positive number
1.33 is a positive number
1e5 is a positive number
1e-4 is a positive number
+1 is a positive number
+1.65 is a positive number
+1e4 is a positive number
1,000 is not a positive number
-1 is not a positive number
-1.234 is not a positive number
-1e5 is not a positive number
-1,000 is not a positive number
a is not a positive number
b is not a positive number
a1b is not a positive number
ab1 is not a positive number
1ab is not a positive number
a b c is not a positive number
This leaves us (I believe) with just the issue of an input containing 1 or more commas, which could be handled by stripping out the comma(s) using whatever method fits your fancy.
Related
I am messing around with something on bash (I am very new to it).
I have a floating point number.
I want to to be able to check if there is any digits after the decimal point from 1-9 in order to determine whether it is a whole number - and do it within an if-else statement.
for example
if(*number does have a 1-9 digit after decimal*)
then
echo 'Number is not a whole number'
else
echo 'Number is a whole number'
fi
Dabbled with grep and REGEX but don't have a great grasp of it yet
With a regex:
x=1.123456789
if [[ "$x" =~ \.[0-9]{1,9}$ ]]; then
echo 'Number is not a whole number'
else
echo 'Number is a whole number'
fi
Output:
Number is not a whole number
Mac_3.2.57$cat findWhole.bash
#!/bin/bash
for x in 1.123456789 0001230045600.00 1.000000 1 1. 1.. 0002 .00 22.00023400056712300 1.00 .
do
if [[ "$x" =~ ^[0-9]*\.[0-9]*[1-9][1-9]*[0-9]*$ ]]; then
echo "$x is not a whole number"
elif [[ "$x" =~ ^[0-9][0-9]*\.?0*$|^\.00*$ ]]; then
echo "$x is a whole number"
else
echo "$x is not a number"
fi
done
Mac_3.2.57$./findWhole.bash
1.123456789 is not a whole number
0001230045600.00 is a whole number
1.000000 is a whole number
1 is a whole number
1. is a whole number
1.. is not a number
0002 is a whole number
.00 is a whole number
22.00023400056712300 is not a whole number
1.00 is a whole number
. is not a number
Mac_3.2.57$
So I admit, I am a complete noob with bash scripting and this assignment is completely dominating me. It is stated above. I believe I managed to figure out the first part in regard to the user input, printing out the amount of terms, and carrying out the correct operation. However, feel free to make suggestions if you notice an error or something that is not best practice. What I am struggling to figure out how to print the sum of the terms that the user has input. Any assistance is appreciated, thank you. My code this far along which is only tasked 1 is listed below; thanks in advance.
Task 3: Find the terms of a sequence given by the rule Term = an² + bn + c, where a and b and c are integers specified by the user and n is a positive integer. This task should give the user two options:
Option 1) Find a limited number of terms of the sequence and print them in order (for example, if the user choses a=3, b=4, and c=1 the first few terms of this sequence are: 8, 21, 40, 65, 96… ). The user also specifies how many terms the program should print. In addition, the program should print the sum of the terms found.
Option 2) Find a term in a position chosen by the user and determine whether this term is a multiple of a number chosen also by the user. For example, for the above sequence where a=3, b=4 and c=1, if the user requires to print the 10th term and to check whether this term is a multiple of 3, the program should print:
341 is not a multiple of 3.
#!/bin/bash
#user selects values for a, b, c
read -p "Please provide value to a:" a
read -p "Please provide value to b:" b
read -p "Please provide value to c:" c
#menu begins
echo "SELECT ONE OPTION";
echo "1. Option1- Find Limited Number of terms of the sequence"
echo "2. Option2- Find a term in a position"
echo -n "Enter your menu choice [1-2]:"
#menu ends
read choice
case $choice in
1) read -p "please provide number of terms to print:" num
n=1
arr=()
while [ $n -le $num ]
do
echo term=$(($a*$n^2+$b*$n+$c))
n=$(( n + 1))
arr+=("$term")
done
;;
After 10 hours of trying to figure out how to execute this task, I've tried quite a few things. However, as I stated I was a noob, I believe they were all just from lack of experience and definitely errors on my end.
Good practice is to only continue with validated inputs.
You should normally include logic similar to the following code segment for each such input:
a=""
while [ -z "${a}" ]
do
echo ""
read -p "Please provide value to a => " a
if [ -n "${a}" ]
then
if [ $a -lt 0 ]
then
echo "\t Invalid integer input. Please try again ..."
a=""
fi
fi
done
Of course, the validation conditions would fit the context.
This version of the script addresses the issue of incorrect operator for the exponential.
It also makes progressive and more explicit reporting of the assignments (development troubleshooting practices until logic is proven).
The way you are trying to assign the value to "term" is improper. You cannot embed that into an echo statement. It must stand on its own before doing the echo.
Again, I prefer explicit assignment of individual terms in the array.
#!/bin/bash
#Question: https://stackoverflow.com/questions/74618838/how-to-print-sum-of-user-terms-that-was-produced-using-a-formula-where-user-sele/74620056#74620056
get_a(){
a=""
while [ -z "${a}" ]
do
echo ""
read -p "Please provide value to a => " a
if [ -n "${a}" ]
then
if [ $a -lt 0 ]
then
echo -e "\t Invalid integer input. Please try again ..."
a=""
fi
fi
done
}
#get_a
a=3
b=4
c=1
# Expect Sequence: 8, 21, 40, 65, 96…
#read choice
choice=1
case $choice in
1 ) #read -p "How many terms would you like to print => " num
num=3
n=1
arr=()
while [ ${n} -le ${num} ]
do
printf "\n\t n = ${n} ...\n"
printf "\t\t$(( ${a}*${n}**2 )) \n\t\t$(( ${b}*${n} )) \n\t\t$(( ${c} ))\n"
term=$(( ${a}*${n}**2 + ${b}*${n} + ${c} ))
printf "\t term = ${term} ...\n"
arr[${n}]=${term}
n=$(( n+1 ))
done
echo ""
for i in ${!arr[#]};
do
echo " arr[${i}] = ${arr[${i}]}"
done
;;
* ) ;;
esac
Session output looks like this:
ericthered#OasisMega1:/0__WORK$ ./test_61.sh
n = 1 ...
3
4
1
term = 8 ...
n = 2 ...
12
8
1
term = 21 ...
n = 3 ...
27
12
1
term = 40 ...
arr[1] = 8
arr[2] = 21
arr[3] = 40
ericthered#OasisMega1:/0__WORK$
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
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.
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