This question already has answers here:
Why should there be spaces around '[' and ']' in Bash?
(5 answers)
Closed 6 years ago.
I wrote a function in bash script. However, it's complaining about syntax. I really can't see what is it..... the error message is [: missing `]'
addem() {
if [ $# -eq 0] || [ $# -gt 2 ]
then
echo -1
elif [ $# -eq 1 ]
then
echo $[ $1 + $1 ]
else
echo $[ $1 + $2 ]
fi
}
You need a space before the first ]. That is:
change:
if [ $# -eq 0] || [ $# -gt 2 ]
to:
if [ $# -eq 0 ] || [ $# -gt 2 ]
Try:
if [ $# -eq 0 ] || [ $# -gt 2 ]
(There was no space between 0 and ].)
indyK1ng: The "#" is not treated as a comment, since the "$" escapes the next character. The "$#" is an internal variable representing the number of positional parameters that exist at the current context. This can be thought of as the number of command line arguments to the shell script, but that array can be reset using the "set -- [args]" built in.
Joakim Elofsson: The overall structure of the if statement is correct, the ";" is only required before the "then" and before the "fi" if those are not listed on a separate line.
The problem is the space between the "0" and the bracket. Bash requires that brackets used to delimit conditional expressions be set off with at least a single space from the expression.
if [ $# -eq 0] || [ $# -gt 2 ] # Wrong
if [ $# -eq 0 ] || [ $# -gt 2 ] # Correct
On an additional note, the two conditional expressions can be combined. The operator association will ensure that everything works out.
if [ $# -eq 0 -a $# -gt 2 ] # Even Better
I tend to prefer the expanded features offered with double brackets for expression evaluation. Note that the combination of the two evaluations is done with a different operator. I find this to be more readable.
if [[ $# -eq 0 || $# -gt 2 ]] # My preference
Later in the script, the use of single brackets for integer addition is not recommended. The single brackets are evaluating an expression to a boolean. Double parens are used for integer math.
echo $[ $1 + $1 ] # Evaluation of an expression
echo $(( $1 + $1 )) # Integer math
Bash is sensitive to spaces. In your first line, replace if [ Y -eq X] with [ Y -eq X ] (space before the "]")
I would use extended test constructs (BASH) as demonstrated bellow. I think it would reduce the no of characters and increase readability (at least for programmers). :-)
addem() {
if (( $# == 0 || $# > 2 ))
then
echo -1
elif (( $# == 1 ))
then
echo (( $1 + $1 ))
else
echo (( $1 + $2 ))
fi
}
You should avoid brackets and use test instead:
if test $# -eq 0 || test $# -gt 2
then
echo -1
elif test $# -eq 1
then
echo $(( $1 + $1 ))
else
echo $(( $1 + $2 ))
fi
Getting a better shell style will make you much better. :)
Related
i have the error named in the tittle in shell scripts when i execute this:
if [ $[ $op1 % $op2 ] == 0 ] and [ $res -ne 0 ]
then
resp
else
divi
fi
thanks.
Your first line violates several shell syntax rules.
if [ $[ $op1 % $op2 ] == 0 ] and [ $res -ne 0 ]
and has no meaning in a shell. Just like in C the correct syntax is &&.
And math expressions use $(( ... )).
So you probably meant:
if [ $(( $op1 % $op2 )) == 0 ] && [ "$res" -ne 0 ]
I also added quoting to $res as otherwise expansion takes place. E.g. if $res equals *, it would not compare * to zero but it would expand *, replacing it with the first filename in the current directory and this could cause the test to be true despite $res being *. To prevent this, you must quote $res. You don't need quoting for $op1 and $op2 as in math expression no shell expansion is performed.
I'm attempting to append to a file this pseudo code:
if [ `expr $MOD % 5` -eq 0 ]; then.
I did it on shell as:
echo if [ `expr $MOD % 5` -eq 0 ]; then
But it gives me a syntax error near unexpected token 'then'. I can't figure out where I'm going wrong.
Use single quotes:
$ echo 'if [ `expr $MOD % 5` -eq 0 ]; then'
if [ `expr $MOD % 5` -eq 0 ]; then
If I am reading this right, you are trying to append this actual text to a file?
if [ `expr $MOD % 5` -eq 0 ]; then
Then the issue is your command structure. You used this:
echo if [ `expr $MOD % 5` -eq 0 ]; then
This is actually two commands as far as the shell is concerned, due to the semicolon. So it is the same as:
echo if [ `expr $MOD % 5` -eq 0 ]
then
Since then is not normally a valid command, and this is outside the context of a shell conditional (for instance if), the shell doesn't know what to do with it.
What you need to do is quote the entire thing as a string and pass that to echo.
echo 'if [ `expr $MOD % 5` -eq 0 ]; then'
Using single quote (') rather than double quote (") is important. If you use double quote, then the bit in backticks (expr $MOD % 5) would be evaluated instead of passed to the file as-is.
So I'm writing a bash shell script, and my first few lines looks like this:
if ! [ $# -eq 0 || $# -eq 1 ]; then
echo -e "Usage: myScriptName [\e[3mdir\e[0m] [\e[3m-f file\e[0m]"
exit 1
fi
But when I run it, it says "[: missing `]'". I don't see a missing ], and nothing except the ; is touching the ], so what am I missing?
You cannot use operators like || within single-brace test expressions. You must either do
! [[ $# -eq 0 || $# -eq 1 ]]
or
! { [ $# -eq 0 ] || [ $# -eq 1 ]; }
or
! [ $# -eq 0 -o $# -eq 1 ]
The double-brace keyword is a bash expression, and will not work with other POSIX shells, but it has some benefits, as well, such as being able to do these kinds of operations more readably.
Of course, there are a lot of ways to test the number of arguments passed. The mere existence of $2 will answer your question, as well.
In my case I got this error with the following:
if [ $# -eq 1]; then
Notice that there is no space between the 1 and the ]. Adding a space fixed the error.
In some cases this error happens even if everything looks fine as #kojiro mentioned above. in such cases a simple and proper line-break will help. if-statement where you are checking with || should have a line-break from it's prior-line of code.
What is the difference between =, == and -eq in shell scripting?
Is there any difference between the following?
[ $a = $b ]
[ $a == $b ]
[ $a -eq $b ]
Is it simply that = and == are only used when the variables contain numbers?
= and == are for string comparisons
-eq is for numeric comparisons
-eq is in the same family as -lt, -le, -gt, -ge, and -ne
== is specific to bash (not present in sh (Bourne shell), ...). Using POSIX = is preferred for compatibility. In bash the two are equivalent, and in sh = is the only one that will work.
$ a=foo
$ [ "$a" = foo ]; echo "$?" # POSIX sh
0
$ [ "$a" == foo ]; echo "$?" # bash-specific
0
$ [ "$a" -eq foo ]; echo "$?" # wrong
-bash: [: foo: integer expression expected
2
(Note: make sure to quote the variable expansions. Do not leave out the double-quotes above.)
If you're writing a #!/bin/bash script then I recommend using [[ instead. The double square-brackets [[...]] form has more features, a more natural syntax, and fewer gotchas that will trip you up. For example, double quotes are no longer required around $a:
$ [[ $a == foo ]]; echo "$?" # bash-specific
0
See also:
What's the difference between [ and [[ in Bash?
It depends on the Test Construct around the operator. Your options are double parentheses, double brackets, single brackets, or test.
If you use ((…)), you are testing arithmetic equality with == as in C:
$ (( 1==1 )); echo $?
0
$ (( 1==2 )); echo $?
1
(Note: 0 means true in the Unix sense and a failed test results in a non-zero number.)
Using -eq inside of double parentheses is a syntax error.
If you are using […] (or single brackets) or [[…]] (or double brackets), or test you can use one of -eq, -ne, -lt, -le, -gt, or -ge as an arithmetic comparison.
$ [ 1 -eq 1 ]; echo $?
0
$ [ 1 -eq 2 ]; echo $?
1
$ test 1 -eq 1; echo $?
0
The == inside of single or double brackets (or the test command) is one of the string comparison operators:
$ [[ "abc" == "abc" ]]; echo $?
0
$ [[ "abc" == "ABC" ]]; echo $?
1
As a string operator, = is equivalent to ==. Also, note the whitespace around = or ==: it’s required.
While you can do [[ 1 == 1 ]] or [[ $(( 1+1 )) == 2 ]] it is testing the string equality — not the arithmetic equality.
So -eq produces the result probably expected that the integer value of 1+1 is equal to 2 even though the right-hand side is a string and has a trailing space:
$ [[ $(( 1+1 )) -eq "2 " ]]; echo $?
0
While a string comparison of the same picks up the trailing space and therefore the string comparison fails:
$ [[ $(( 1+1 )) == "2 " ]]; echo $?
1
And a mistaken string comparison can produce a completely wrong answer. 10 is lexicographically less than 2, so a string comparison returns true or 0. So many are bitten by this bug:
$ [[ 10 < 2 ]]; echo $?
0
The correct test for 10 being arithmetically less than 2 is this:
$ [[ 10 -lt 2 ]]; echo $?
1
In comments, there is a question about the technical reason why using the integer -eq on strings returns true for strings that are not the same:
$ [[ "yes" -eq "no" ]]; echo $?
0
The reason is that Bash is untyped. The -eq causes the strings to be interpreted as integers if possible including base conversion:
$ [[ "0x10" -eq 16 ]]; echo $?
0
$ [[ "010" -eq 8 ]]; echo $?
0
$ [[ "100" -eq 100 ]]; echo $?
0
And 0 if Bash thinks it is just a string:
$ [[ "yes" -eq 0 ]]; echo $?
0
$ [[ "yes" -eq 1 ]]; echo $?
1
So [[ "yes" -eq "no" ]] is equivalent to [[ 0 -eq 0 ]]
Last note: Many of the Bash specific extensions to the Test Constructs are not POSIX and therefore may fail in other shells. Other shells generally do not support [[...]] and ((...)) or ==.
== is a bash-specific alias for = and it performs a string (lexical) comparison instead of a numeric comparison. eq being a numeric comparison of course.
Finally, I usually prefer to use the form if [ "$a" == "$b" ]
Several answers show dangerous examples. The OP's example, [ $a == $b ], specifically used unquoted variable substitution (as of the October 2017 edit). For [...] that is safe for string equality.
But if you're going to enumerate alternatives like [[...]], you must inform also that the right-hand-side must be quoted. If not quoted, it is a pattern match! (From the Bash man page: "Any part of the pattern may be quoted to force it to be matched as a string.").
Here in Bash, the two statements yielding "yes" are pattern matching, other three are string equality:
$ rht="A*"
$ lft="AB"
$ [ $lft = $rht ] && echo yes
$ [ $lft == $rht ] && echo yes
$ [[ $lft = $rht ]] && echo yes
yes
$ [[ $lft == $rht ]] && echo yes
yes
$ [[ $lft == "$rht" ]] && echo yes
$
I am trying to make this piece of code accept either user given 4 value or a "/" to accept the default value.
#!/bin/bash
$komp=1
while [ ${#nbh[#]} -ne `expr 4 \* $komp` || ${nbh[0]} -ne "/" ]
do
echo "Enter 4 element or / to accept default"
read -a nbh
if [ ${#nbh[#]} -ne `expr 4 \* $komp` || ${nbh[0]} -ne "/" ]
then
echo "Wrong!!"
else
if [ nbh -eq "/" ]
then
declare -a nbh=('1' '0' '1' '1')
fi
fi
done
In present situation, it is giving error:
./mini.sh: line 3: [: missing `]'
./mini.sh: line 3: -ne: command not found
Kindly help.
The fundamental problem is that you can't do a boolean expression that way.
while [ expr1 || expr2 ] # WRONG
does not work because the shell parses it as two commands: [ expr (the command [ with one argument "expr1") and expr2 ] (the command expr2 with one argument "]"). This is an error, because the [ command requires that its last argument be the literal string ]. It is easier to understand the syntax if you use the test command instead of [, but either of the following will work:
while test expr1 || test expr2
while [ expr1 ] || [ expr2 ]
while [ expr1 -o expr2 ]
while test expr1 -o expr2
#!/bin/bash
komp=1
default=(1 0 1 1)
prompt="Enter 4 elements or / to accept default: "
valid_input=0
while ((!valid_input)) && read -a nbh -p "$prompt"; do
if ((${#nbh[#]}==1)) && [[ ${nbh[0]} = / ]]; then
for ((i=0,nbh=();i<komp;++i)); do nbh+=( "${default[#]}" ); done
fi
if ((${#nbh[#]} != 4*komp)); then
echo "Wrong!!"
continue
fi
valid_input=1
done
if ((!valid_input)); then
echo >&2 "There was an error reading your input. Do you have a banana jammed in your keyboard?"
exit 1
fi
# Here, all is good
Now you'll also want to check that user's inputs are valid numbers.
Please read (and understand) the answer I provided to your other question. (if you actually had done so, you wouldn't have asked this question).