I am having difficulty getting a for loop to take user input in the form of an argument to a function I created.
#!/bin/bash
number1="$1" #Assume user input 5
loops="$2" #Assume user input 5
if [[ ${number1} && ${loops} =~ ^-?[0.00-9.99]+$ ]];then
for number2 in {1..${loops}}
do
Product=$(echo "${number1} * ${number2}" | bc -l)
echo "${number1} * ${number2} = ${Product}"
if test ${number2} -eq 7;then
{ echo "----------------------"; echo "${number2} is the best number."; echo "----------------------"; continue; }
elif test ${number2} -eq 11;then
{ echo "------------------------------"; echo "${number2} is pretty awesome as well."; echo "------------------------------"; continue; }
fi
done
else
{ echo "Please try again with a valid numerical entry."; exit 1; }
fi
This script does not run when the user inputs an integer for the variable "loops", and any number for "number1". number1 = 5 in this case. It returns the error:
(standard_in) 1: syntax error
5 * {1..5} =
/home/$USER/For_Loop_Multiplication.sh: line 9: test: {1..5}: integer expression expected
/home/$USER/For_Loop_Multiplication.sh: line 11: test: {1..5}: integer expression expected
If I instead directly input an end bound on the number of loops directly into the script like the following, and number1 = 5, it runs fine:
#!/bin/bash
number1="$1" #Assume user input 5
if [[ ${number1} =~ ^-?[0.00-9.99]+$ ]];then
for number2 in {1..5}
do
Product=$(echo "${number1} * ${number2}" | bc -l)
echo "${number1} * ${number2} = ${Product}"
if test ${number2} -eq 7;then
{ echo "----------------------"; echo "${number2} is the best number."; echo "----------------------"; continue; }
elif test ${number2} -eq 11;then
{ echo "------------------------------"; echo "${number2} is pretty awesome as well."; echo "------------------------------"; continue; }
fi
done
else
{ echo "Please try again with a valid numerical entry."; exit 1; }
fi
It returns the result:
5 * 1 = 5
5 * 2 = 10
5 * 3 = 15
5 * 4 = 20
5 * 5 = 25
Essentially what I think is happening is that the script seems to be placing the entire range as the value number2, which is defined as the iterator in the for loop. Since the input for the variable "loops" is an integer, there should be no difference between asking the user for a range and placing it in the loop, or simply setting it as a default when I write the script. However, there apparently is a difference... Any insight into solving this problem is appreciated. Thanks.
The problem is this line:
for number2 in {1..${loops}}
This is a question of precedence. As explained in man bash
:
The order of expansions is: brace expansion; tilde expansion, parameter and variable expansion, arithmetic expansion, and command substitution (done in a left-to-right fashion); word splitting; and pathname expansion.
So, brace expansion happens before variable expansion. Therefore, when the braces are expanded, $loops
has not been evaluated to 5
. This means that {1..$loops}
(you don't need the second {}
) expands to the string {1..5}
and not the sequence of numbers from 1 to 5. The same thing happens if you use a string instead of a variable:
$ echo {1..5} ## works: prints a sequence
1 2 3 4 5
$ echo {1..foo} ## fails: prints a string with no expansion
{1..foo}
As a workaround, you can use seq
:
for number2 in $(seq 1 "$loops"); do ...
Or, even better, the right loop for the job:
for((number2=0;number2<=$loops; number2++)); do ...
Note: As a general rule, you should also always quote your variables.
Collected from the Internet
Please contact [email protected] to delete if infringement.
Comments