I have a side-project in BASH for fun, and I have this code snippet (ARRAY[0] is 8):
while [ $ALIVE == true ]; do
$ARRAY[0] = ${ARRAY[0]} - 1
echo ${ARRAY[0]}
done
However, it comes back with this error:
line 16: 8[1]: command not found
I just started working in BASH, so I might be making an obvious mistake, but I've searched and searched for an answer to a problem like this and came up with no result.
The smallest change is simply:
ARRAY[0]=$(( ${ARRAY[0]} - 1 ))
Note:
No $ before the name of the variable to assign to (foo=, not $foo=)
No spaces around the = on the assignment
$(( )) is the syntax to enter a math context (and expand to the result of that operation).
Related
I would like to compare a number, which is the output of a command, with a constant and do some manipulation. That is, if $id < 10, I want to see 590$id and if it is above 10, I want to see 59$id.
I found that expr doesn't working here:
ID=3
NUM=59$ID
if [ `expr $ID` -lt 10]; then
NUM=590$ID
fi
echo $NUM
The output of the code is 593 and not 5903. Even, $(($ID + 5900)) -lt 5910 writes 593.
How can I fix that?
Could you please try following.
cat script.sh
#!/bin/bash
ID=$(printf "%02d" 3 )
##NUM=59$ID ##Commented this to check if, condition is getting satisfied or not. Doesn't seem to be fit here.
(( $ID < 10 )) && NUM="59$ID"
echo "$NUM"
Output will be 5903 after running above code.
Don't use expr. It's old and tricky.
Don't use backticks `. They are discouraged and $( ... ) is preferred.
For arithmetic comparisons use arithmetic expansions. Just
if (( ID < 10 )); then
Note that bash is space aware and your script has a syntax error, it is missing a space - the 10]; should be 10 ];.
Note that by convention uppercase variables should be used for exported variables.
Looking at your code I think you just want:
NUM=$((5900 + ID))
I'm a bit stuck with something. I have a for loop like this:
#!/bin/bash
for i in {10..15}
do
I want to obtain the last digit of the number, so if i is 12, I want to get 2. I'm having difficulties with the syntax though. I've read that I should convert it into a character array, but when I do something like:
j=${i[#]}
echo $j
I don't get 1 0 1 1 1 2 and so on...I get 10, 11, 12...How do I get the numbers to be split up so I can get the last one of i, when I don't always know how many digits will make up i (ex. it may be 1, or 10, or a 100, etc.)?
Trick is to treat $i like a string.
for i in {10..15}; do j="${i: -1}"; echo $j; done
Of course, you do not need to assign to a variable if you don't want to:
for i in {10..15}; do echo "${i: -1}"; done
This answer which uses GNU shell parameter expansion is the most sensible method, I guess.
However, you can also use the double parenthesis construct which allows C-style manipulation of variables in Bash.
for i in {10..15}
do
(( j = i % 10 )) # modulo 10 always gives the ones' digit
echo $j
done
This awk command could solve your problem:
awk '{print substr($0,length,1)}' test_file
I'm assuming that the numbers are saved in a file test_file
If you want to use for loop:
for i in `cat test_1`
do
echo $i |tail -c 2
done
This question already has answers here:
How can I compare two floating point numbers in Bash?
(22 answers)
Floating point comparison in shell
(7 answers)
Closed 4 years ago.
So want to turn this function, whose output is a number. The number is curled through some json file thats irrelevant.
#error input 1
if (($(masterfunc) >= 1)); then
#I've also tried
#error input 2
if (($(masterfunc | bc -l) >= 1)); then
I get these this error, which I'm assuming is because its outputing it as a letter or command and not as a number.
#error output 1
((: 1.00048333447157914468 >= 1: syntax error: invalid arithmetic
operator (error token is ".00048333447157914468 >= 1")
#error output 2
((: .99989817794934530799 >= 1: syntax error: operand expected (error
token is ".99989817794934530799 >= 1")
I'm assuming this is some floating point arithmetic problem, but then it should of been solved through bc?
I'm new to bash so if the problem is some unrelated syntax error I apologize.
This is actually rather complicated. The shell doesn't understand real numbers at all, so you have to get something else (like bc) to do the comparison and output something simpler that bash can understand. The simplest way I see to do this is:
if [ $(echo "$(masterfunc) >= 1" | bc) -eq 1 ]; then
Explanation, step by step:
echo "$(masterfunc) >= 1" runs the masterfunc function, adds ">= 1" to its output, and sends the result (something like "1.00048333447157914468 >= 1") to standard output.
echo "$(masterfunc) >= 1" | bc runs the above and pipes it to bc, which will do the comparison and print "1" if the masterfunc output is greater than or equal to 1, "0" if it's less. Note: you can try running this by hand and see how it works.
This "1"/"0" output is more along the lines of what bash can understand, but we still need to actually tell bash what to make of it.
[ $(echo "$(masterfunc) >= 1" | bc) -eq 1 ] runs the above, captures its output with $( ), and embeds that in a test expression. Basically, depending on the output from bc, this is equivalent to either [ 1 -eq 1 ] or [ 0 -eq 1 ].
Use this:
if (( $(printf '%s >= 1\n' "$(masterfunc)" | bc -l) )); then ...
In a for loop I am looking to find out: If Array1 length matches Array2 length then break the for loop.
Shellcheck throws an error (while the script runs fine)
if [[ "${!Array1[#]}" == "${!Array2[#]}" ]] ; then
break;
fi
^-- SC2199: Arrays implicitly concatenate in [[ ]]. Use a loop (or explicit * instead of #).
I'm still learning bash and my teacher said "Always verify with Shellcheck" and to "always place conditionals in double [[ ]]" and to "never use * for array length"
The error(s) are removed with the correction
if [ "${!Array1[*]}" == "${!Array2[*]}" ] ; then
break;
fi
I was wondering what is the best practice here?
Your code is partly correct. The problem is, that you are expanding the array's indicies with th ! operator, and not the length by using the # operator.
Thus a warning about implicit concatenation is issued for both uses of ${array[#]}, as the list of indicies is 0 1 2 3 .... Nevertheless your code is working, as two non associative bash arrays with equal length will have identical index lists 0 1 2 .. N.
To get rid of the warning, you should replace ${!array[#]} with ${#array[#]}. Of course, using ${!array[*]} will also suppress the warning, but that is definitely not what you want to do here, as you would continue comparing index lists.
For further reading: The author of shellcheck has explained the concatenation issue here in detail.
Nyronium's works well and explains the solution perfectly.
I also found a solution that utilities # to check the array length for the condition.
Sorry I did not have this example script before, as I wrote it to test logic afterwards.
Example
#!/bin/bash
array1=(1 2 3)
array2=()
echo "array1 length: ${#array1[#]}" #output :3
for i in {1..10} ; do
echo "array2 length: ${#array2[#]}"
array2+=("$i")
#I want to exit when array2 = a length of 3
if [[ "${#array1[#]}" == "${#array2[#]}" ]] ; then
echo "exit"
break
fi
done
echo "final array1 length: ${#array1[#]} vs array2 length: ${#array1[#]}"
Result: final array1 length: 3 vs array2 length: 3
I am new to bash scripting. Now, the question is self explanatory. I want to print the values 2^0, 2^1, 2^2, 2^3, 2^4, 2^5 using loop in bash.
I tried ..
for i in {0...5}; do echo 2^$i; done
result:
2^{0...5}
please suggest a solution
This is the correct form:
for i in {0..5}; do echo $((2**i)); done
Where { .. } is the range operator and $(( )) the arithmetical evaluation operator.
Note that the power operator in Bash is written ** and not ^.
Edit: Roberto Reale's answer is much better for this purpose, as it's shorter and simpler.
2^$i; won't work unfortunately, as bash doesn't support that operator.
You could try adding this
pow()
{
echo $(( ${1:?} ** ${2:?} ))
}
to your code (using it like pow [base] [exponent] (without the brackets of course)).
(Bare in mind I havent't tested this, so this may not work as expected)
Source
You could try this code also,
$ for i in {0..5}; do awk -v var=$i 'BEGIN{print 2^var}'; done
1
2
4
8
16
32