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

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

Related

Nice way of assigning true or false to value in bash [duplicate]

Can someone explain how to perform Boolean operations and store them in variables in Bash?
I tried:
A=true
B=false
C=!$A
D=$A && $B
echo $C
echo $D
I also tried without dollars, with [], with {}, ()... How can one do such a simple operation in bash?
result in console are:
!true
true
It seems they are always treated as strings.
You deduced right, bash variables by default contain strings, and its values are treated as strings.
You can use the declare built-in command to explicitly say they store integers (declare -i myintvar), or indexed arrays (declare -a myarr), or associative arrays (declare -A mymap), etc., but not booleans.
The closest you can get to booleans is to use integer values 0 and 1 and evaluate expressions as arithmetic expressions with the (( expr )) command (bash-specific), or with arithmetic expansion $(( expr )) (POSIX-compatible). Those commands evaluate expr according to rules of shell arithmetic.
For example:
A=1
B=0
(( C = \!A )) # logical negation ==> C = 0
(( D = A && B )) # logical AND ==> D = 0
E=$(( A ^ B )) # bitwise XOR ==> E = 1
In bash, you can also use declare -i and let:
declare -i E='A||B' # equivalent to: E=$((A||B)), or ((E=A||B))
let C='!A' # equivalent to: C=$((\!A)), or ((C=\!A))
which are a longer way of saying ((..)) or $((..)). They both force arithmetic evaluation of the expressions given.
Note that ! has a special meaning in most shells (including bash), it causes history expansion. To prevent it, we must escape it with a backslash, or quote it.
Unfortunately, bash does not support boolean variables in a proper meaning. There is no "true" and "false" constants as in programming languages. Instead, /bin/true and /bin/false are two executables that don't do anything except return exit status 0 or 1. Contrary to common logic, exit status 0 is a synonim for "true" and 1 is a synonim for "false". The closest you can get to evaluating boolean expressions is either
[[ expr ]] which returns a exit status 0 or 1 depending on evaluating expr
&& and || (these are conditionals depending on last command's exit status)
[ which is actually an executable with a silly name (not part of bash) that supports some basic expressions
if...elif..else..fi which you can use to your advantage to manipulate variables within the workflow
like this?
t=true
f=false
# if $t; then echo Hi; fi
Hi
# if $f; then echo Hi; fi
# if ! $f; then echo Hi; fi
Hi
# if ! ($t && $t); then echo Hi; fi
# if ($t && $t); then echo Hi; fi
Hi

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

Using variables in Bash boolean expressions

Can someone explain how to perform Boolean operations and store them in variables in Bash?
I tried:
A=true
B=false
C=!$A
D=$A && $B
echo $C
echo $D
I also tried without dollars, with [], with {}, ()... How can one do such a simple operation in bash?
result in console are:
!true
true
It seems they are always treated as strings.
You deduced right, bash variables by default contain strings, and its values are treated as strings.
You can use the declare built-in command to explicitly say they store integers (declare -i myintvar), or indexed arrays (declare -a myarr), or associative arrays (declare -A mymap), etc., but not booleans.
The closest you can get to booleans is to use integer values 0 and 1 and evaluate expressions as arithmetic expressions with the (( expr )) command (bash-specific), or with arithmetic expansion $(( expr )) (POSIX-compatible). Those commands evaluate expr according to rules of shell arithmetic.
For example:
A=1
B=0
(( C = \!A )) # logical negation ==> C = 0
(( D = A && B )) # logical AND ==> D = 0
E=$(( A ^ B )) # bitwise XOR ==> E = 1
In bash, you can also use declare -i and let:
declare -i E='A||B' # equivalent to: E=$((A||B)), or ((E=A||B))
let C='!A' # equivalent to: C=$((\!A)), or ((C=\!A))
which are a longer way of saying ((..)) or $((..)). They both force arithmetic evaluation of the expressions given.
Note that ! has a special meaning in most shells (including bash), it causes history expansion. To prevent it, we must escape it with a backslash, or quote it.
Unfortunately, bash does not support boolean variables in a proper meaning. There is no "true" and "false" constants as in programming languages. Instead, /bin/true and /bin/false are two executables that don't do anything except return exit status 0 or 1. Contrary to common logic, exit status 0 is a synonim for "true" and 1 is a synonim for "false". The closest you can get to evaluating boolean expressions is either
[[ expr ]] which returns a exit status 0 or 1 depending on evaluating expr
&& and || (these are conditionals depending on last command's exit status)
[ which is actually an executable with a silly name (not part of bash) that supports some basic expressions
if...elif..else..fi which you can use to your advantage to manipulate variables within the workflow
like this?
t=true
f=false
# if $t; then echo Hi; fi
Hi
# if $f; then echo Hi; fi
# if ! $f; then echo Hi; fi
Hi
# if ! ($t && $t); then echo Hi; fi
# if ($t && $t); then echo Hi; fi
Hi

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

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

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

Resources