I am trying to insert names and numbers in a text file. I have wrote a short script for the learning purpose.
v= expr $# % 2
echo $v
if [ "$v" -eq 0 ]; then
i=1
while [ "$i" -lt $# ]
do
echo "$i $i+1" >> database
i=$((i+1))
done
echo "User(s) successfully added \n\v"
else
echo "Arguments are not complete";
fi
When i enter two arguments, the shell output is as follows
0 # (The value of variable v)
./myscript: line 3: [: : integer expression expected
Arguments are not complete # (else statement is executed)
When i replace -eq to == in line 3 (if statement), error msg is gone but still the IF statement doesn't execute as i expect.
0 # (output of variable v)
Arguments are not complete # (else statement is executed)
You need to enclose the variable assignment in $(...) ("command substitution"):
v=$(expr $# % 2)
In the if statement, -eq should be correct. Also, to make sure it works, I would use double square brackets (this might depend on the shell you use):
if [[ ${v} -eq 0 ]]; then
The immediate problem is the failure to use command substitution to capture the result of the expr command: v=$( expr $# % 2 ). However,
expr is no longer needed for arithmetic; use an arithmetic expression just as you did to increment i.
v=$(( $# % 2 ))
Related
for i in {1..99}
do
if ([ $((i % 2)) -eq 1 ])
then
echo $i
fi
done
I'm learning bash, and I'm trying to better understand line 3. Why does $((i % 2)) have to be double wrapped in parenthesis, and why can't I put the $ symbole inside next to the i like:
([ (($i % 2)) -eq 1 ])
or
([ ($(i % 2)) -eq 1 ])
?
Everything inside $((...)) is treated as an arithmetic expression. You can use parameter expansion inside an arithmetic expression, but a bare string is interpreted as a variable whose (integer) value is used. You can write
if [ $(( i % 2 )) -eq 1 ]
to check if i is odd. You can also check for equality inside the expression, as $(( x == y )) evaluates to 1 if x == y and 0 otherwise, but you would still have to compare that value to something.
In bash, you can use the arithmetic command, which has an exit status of 0 if the resulting value is non-zero, and 1 otherwise. This lets you write
if (( i % 2 == 1 )); then
$(( expression )) is the syntax for evaluating an arithmetic expression, and replacing this syntax with the result of that expression. It's documented in the Bash Manual here;
The syntax of arithmetic expressions is described here. Putting $ before variable names is optional, so you can also write it as $(($i % 2)).
You have to wrap it in two parentheses because $(...) already has a meaning, it's used for command substitution: $(some command) executes some command and is then replaced with the output of the command.
You don't need parentheses around [ ... ]. The normal way to write your if statement would be
if [ $((i % 2)) -eq 1 ]
You can also write it as
if (( i % 2 == 1 ))
(( expression )) evaluatees the arithmetic expression, and then sets its exit status depending on whether the result is zero or non-zero.
Since you specify bash, simplest is
for i in {1..99}
do if ((i % 2))
then echo $i
fi
done
the ((i % 2)) will return i mod 2, which will always be zero or one. This particular construct behaves like a C-style boolean, so zero is false and anything else is true (the opposite behavior from [[ ... ]] which uses return code of zero to mean true/ok).
You can also use expr:
for i in {1..99}
do
num=`expr i % 2`
if (( num == 1 ))
then
echo $i
fi
done
for i in {1..99}
do
if ([ $((i % 2)) -eq 1 ])
then
echo $i
fi
done
I'm learning bash, and I'm trying to better understand line 3. Why does $((i % 2)) have to be double wrapped in parenthesis, and why can't I put the $ symbole inside next to the i like:
([ (($i % 2)) -eq 1 ])
or
([ ($(i % 2)) -eq 1 ])
?
Everything inside $((...)) is treated as an arithmetic expression. You can use parameter expansion inside an arithmetic expression, but a bare string is interpreted as a variable whose (integer) value is used. You can write
if [ $(( i % 2 )) -eq 1 ]
to check if i is odd. You can also check for equality inside the expression, as $(( x == y )) evaluates to 1 if x == y and 0 otherwise, but you would still have to compare that value to something.
In bash, you can use the arithmetic command, which has an exit status of 0 if the resulting value is non-zero, and 1 otherwise. This lets you write
if (( i % 2 == 1 )); then
$(( expression )) is the syntax for evaluating an arithmetic expression, and replacing this syntax with the result of that expression. It's documented in the Bash Manual here;
The syntax of arithmetic expressions is described here. Putting $ before variable names is optional, so you can also write it as $(($i % 2)).
You have to wrap it in two parentheses because $(...) already has a meaning, it's used for command substitution: $(some command) executes some command and is then replaced with the output of the command.
You don't need parentheses around [ ... ]. The normal way to write your if statement would be
if [ $((i % 2)) -eq 1 ]
You can also write it as
if (( i % 2 == 1 ))
(( expression )) evaluatees the arithmetic expression, and then sets its exit status depending on whether the result is zero or non-zero.
Since you specify bash, simplest is
for i in {1..99}
do if ((i % 2))
then echo $i
fi
done
the ((i % 2)) will return i mod 2, which will always be zero or one. This particular construct behaves like a C-style boolean, so zero is false and anything else is true (the opposite behavior from [[ ... ]] which uses return code of zero to mean true/ok).
You can also use expr:
for i in {1..99}
do
num=`expr i % 2`
if (( num == 1 ))
then
echo $i
fi
done
This question already has answers here:
Why should there be spaces around '[' and ']' in Bash?
(5 answers)
Closed 5 years ago.
I am fairly new to bash scripting and am struggling with some if-statement syntax.
I have currently written up the following loop:
for (( i = 2; i < $# - 1; i++)); do
if [ $i -ne 0]; then
if [ $i -ne 1]; then
echo "$i was not 1 or 0. Please correct this then try again."
exit 1;
fi
fi
done
This code is supposed to test whether any arguments after the first are either a 1 or a 0.
While the following errors are printed:
./blink.sh: line 36: [: missing `]'
./blink.sh: line 36: [: missing `]'
...the code actually runs fine afterwards (so the errors don't kill the program).
My understanding, however, is that in bash, you put spaces before and after the expression inside the if statement. So this:
if [ $i -ne 0]; then
Becomes:
if [ $i -ne 0 ]; then
However, running this code produces the following:
2 was not 1 or 0. Please correct this then try again.
The main issue I am having with this stems from not understanding how to indirectly reference the positional arguments provided by the execution command. As such, I am confused as to what syntax must be altered to call the objects the arguments point to (in this case, hopefully either a 1 or a 0) rather than the position of the arguments themselves (argument 1, 2, 3...).
Thanks!
EDIT: Altering the question to better fit the advice #randomir provided and clear up what the actual question entails
Based on:
This code is supposed to test whether any arguments after the first are either a 1 or a 0.
I'm assuming you're trying to access positional arguments $2, $3, etc. To make your for loop solution work, you would have to use an indirect reference: ${!i} (see shell parameter expansion). For example, this should work:
#!/bin/bash
for (( i = 2; i <= $#; i++ )); do
if [[ ${!i} -ne 0 ]]; then
if [[ ${!i} -ne 1 ]]; then
echo "$i was not 1 or 0. Please correct this then try again."
exit 1;
fi
fi
done
Note the i running from 2 to number of arguments $#. Also, note the use of recommended and less error-prone [[ .. ]] instead of [ .. ] (otherwise you would have to write [ "${!i}" -ne 0 ], etc).
A simpler solution which avoids the unnecessary indirect referencing looks like this:
#!/bin/bash
while [[ $2 ]]; do
if (( $2 != 0 && $2 != 1 )); then
echo "$2 is neither 0, nor 1"
exit 1
fi
shift
done
We start checking the second argument ($2), use the arithmetic expression (( expr )) testing of value of the second argument, and shift positional arguments to the left by 1 at each iteration (now $3 becomes $2, etc).
I really can't see what the issue is with my script is. I've considered missing quotations or other syntax errors. There's got to be something I'm missing. It's a very simple while loop script...
#!/bin/bash
c=1
while [ $c -le 5 ]
do
echo "Welcone $c times"
c=$(( c++ ))
done
I should mention that I'm running bash in cygwin on windows 7.
thanks for the help
Change:
c=$(( c++ ))
to
(( c=c+1 ))
When Bash sees: (( var)) it will try and 'do some math' on contents... In this case 'c++' == empty string == '0'; c will always be equal to '1' due to 1st assignment...
From the Bash man page on my Linux system (you may need to review this for Cygwin - could be different...):
((expression))
The expression is evaluated according to the rules described below under ARITHMETIC EVALUATION. If the value of the expression is non-zero, the return status is 0; otherwise the return status is 1. This is exactly equivalent to let "expression".
Also:
id++ id--
variable post-increment and post-decrement
++id --id
variable pre-increment and pre-decrement
After a little testing, the 'pre-increment' seems to do what you are after here - note that you may need to declare 'c' as an integer:
typeset -i c=1
while [ $c -le 5 ]
do
echo "Welcone $c times"
c=++c
# (( c=c+1 ))
done
Can someone point out what is wrong with the output.
for i in {0..127} ; do
echo -n [$i]
if [ $i*$j%8 -eq 0 ]; then
echo "\n"
fi
mytool -c "read 0x1540:0xa0:$i*$j"
done
I am trying to format the output into rows containing 8 items each.
I tried the suggestion below and modified my code to
for i in {0..8} ; for j in {0..16}; do
echo -n [$i*$j]
if [[ $i*$j%8 == 0 ]]; then
echo
fi
mytool -c "read 0x1540:0xa0:$i*$j"
done
Above with for i in {0..8} ; for j in {0..16}
I am expecting this to be a nested for loop.I am not very sure if this is how I do a nested loop in bash.
Still the output is not as I expect it.
My output looks like
[0]0x3
[1]0x4
[2]0x21
[3]0x1
[4]0x0
[5]0x0
[6]0x4
[7]0x41
[8]0x84
[9]0x80
[10]0x0
[11]0x0
[12]0x3
[13]0x0
[14]0x43
[15]0x49
[16]0x53
[17]0x43
[18]0x4f
[19]0x2d
[20]0x49
[21]0x4e
[22]0x43
[23]0x20
[24]0x0
[25]0x0
[26]0x9
[27]0x3a
[28]0x37
[29]0x34
[30]0x39
[31]0x34
I want [0] to [7] in ROW1
[8] to [15] in ROW2
and so on.
Use (( )) if you want to do math.
if ((i * j % 8 == 0)); then
Given your problem description I suggest a bit of a rewrite.
for i in {0..15}; do
for j in {0..7}; do
echo -n "[$((i * 8 + j))]"
mytool -c "read 0x1540:0xa0:$i*$j"
done
echo
done
The test command ([ is an alias for test, not syntax) requires the expression to be built up from multiple arguments. This means spaces are critical to separate operators and operands. Since each part is a separate argument, you also need to quote the * so that the shell does not expand it as a file glob prior to calling test/[.
if [ "$i" "*" "$j" % 8 -eq 0 ]; then
The test command expects 7 separate arguments here: $i, *, $j, %, -eq, and 0, which it then assembles into an expression to evaluate. It will not parse an arbitrary string into an expression.
As noted by John Kugelman, there are easier ways to accomplish such arithmetic in bash.