If-statements in Bash Syntax issues produce right answers, while right code shows wrong answers [duplicate] - bash

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).

Related

if statement always goes to the else

I just started learning Bash scripting and i have to do a program that separate between one bit map image to two (the image is broken), I already found on the web how to write loops and statements
but i don't know why my if statement is always goes to the else.
the if is modulo by 2 thats equals to 0
here is the following code
#!/bin/sh
OUTPUT="$(hexdump -v -e '/1 "%02X\n"' merge.bmp)"
echo $OUTPUT
vars=0
count=1
touch one
touch two
for i in $OUTPUT
do
if (($vars%2==0))
then
echo "1"
else
echo "2"
fi
vars=$((vars+count))
done
in the terminal the following error is
./q3.sh: 14: ./q3.sh: 2885%2==0: not found
2
i really don't know why the if always print 2
The shebang line is wrong, it should be:
#!/bin/bash
((expression)) is a bash extension, not available in sh.
The /bin/sh version of the (()) bashism is this:
if test $(($vars % 2)) -eq 0; then
echo "1"
...
fi
Since $(()) knows about variable names, you may even drop the dollar and write
if test $((vars % 2)) -eq 0; then
echo "1"
...
fi

Integer expression expected BASH scripting IF statement

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 ))

syntax error: unexpected end of file trying to run a simple bash script

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

[0]-bash: [: 0*1%8: integer expression expected

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.

solaris simple bash script

I'm trying to execute this simple script in solaris.
I want to sort(numeric) the filenames of the files in source directory and copy the file one by one to another directory. And, I want to print a message after copying every 100 files.
#!/bin/bash
count=0
for i in `ls | sort -n`
do
cp $i ../target
count = $((count+1))
if[ $count%100 -eq 0 ]
then
echo $count files copied
sleep 1
fi
done
this is not working. I tried different things after searching in net.
I get errors like these -
syntax error at line 8: '(' unexpected.
syntax error at line 10: 'then' unexpected.
syntax error at line 13: 'fi' unexpected etc.
What is the problem with this script?
bash version - GNU bash, version 3.00.16(1)-release (sparc-sun-solaris2.10)
The basic problem with the script is spacing. You have spaces where you shouldn't have them:
(wrong) count = $((count+1))
(right) count=$((count+1))
(better) ((count++))
and you're missing spaces where you need them:
(wrong) if[ $count%100 -eq 0 ]
(right) if [ $((count % 100)) -eq 0 ]
(better) if ((count % 100 == 0))
count = $((count+1)) tries to run the command count passing it two arguments, = and the value of count+1. if[ ... tries to run the command if[ because [ is a valid word character; it doesn't automatically start a new token.
Having said all that, I'm puzzled by the unexpected ( error message. Could your bash be too old to recognize $(( syntax? Possibly. It's a very old bash.
count=$((count+1))
if [ `echo $count % 100 | bc` -eq 0 ]
Make these corrections.
Edit: Please try
count=`expr $count + 1`
I see a few errors here. First, you need double quotes around $i in case they have special characters.
Second, you shouldn't ever use
for i in `ls | sort -n`
Instead, try the following
ls -1 | sort -n | while read i
Third, change your if statement to
if ((count%5 == 0))
The (( syntax is bash is made just for integer math.
Fourth, change your counter increment to
((count++))
This is more concise. Also, the space in your version may break things. Remember, spaces matter.

Resources