I tried using this:
$ if [$a == 1] then { echo 'yes'; } fi;
but I get an error:
-bash: syntax error near unexpected token `}'
What is the correct format? I tried several with no luck.
I tried using this:
$ if [$a == 1] then { echo 'yes'; } fi;
but I get an error:
-bash: syntax error near unexpected token `}'
What is the correct format? I tried several with no luck.
[
is just another character, according to bash; it's not self-delimiting. So you need to put spaces around [
and ]
. Although you'd be better off using [[
and ]]
.
And the command following if
(yes, [
is a command) must be terminated with a ;
or a newline.
Finally, ==
(which is not posix, FWIW; posix prefers =
) is string equality, not numeric equality.
So you might have meant:
if [[ $a -eq 1 ]]; then echo yes; fi
But you could use arithmetic evaluation instead:
if ((a == 1)); then echo yes; fi
(In arithmetic evalution, equality is ==
, and you don't need $
before variable names. I know it's confusing.)
For more information about [
: help test
. About [[
: help [[
(which builds on test
). About ((
: help let
. About bash
: man bash
Use:
if [ "$a" = 1 ]; then echo yes; fi
The error reported by bash: -bash: syntax error near unexpected token `}' is an attempt to guide the code writer to the error, but bash can easily get it wrong and signal an error where it isn't.
Actually, there are several errors in the code. But let's reproduce the error that bash reports in a simpler code line:
$ if true then { true; } fi;
bash: syntax error near unexpected token `}'
If the line changes a little, the error is reported at about the same place but a little different:
$ if true then true; fi;
bash: syntax error near unexpected token `fi'
And, this also report an error:
$ if true; then; true; fi;
bash: syntax error near unexpected token `;'
All of that happens because the syntax required (copied from the manual) is:
if list; then list; fi;
where list
is one or several simple commands (or pipes, or compound commands) that end in a newline or a semicolon. Note that, in general, a newline could be replaced with a semicolon and viceversa.
This is valid (no syntax error reported)
if true; then true; fi
This is also valid:
if true
then true
fi
or:
if echo start; true; then echo decision; true; echo next; fi;
Or other variations of newlines and/or semicolons.
Of course, the last semicolon is not required but not forbidden.
Additionally, the [
and ]
require (usually) spaces to be differentiated by bash as words (tokens) and therefore be understood as a test
if [ $a == 1 ]; then { echo 'yes'; } fi; # still subtly incorrect.
But, also, a variable expansion should be quoted ("$a"
), the ==
is valid in bash, but it may be invalid in some other shells, so we rather should use a =
inside single [ ]
, the 'yes'
technically doesn't need to be quoted (even if it is no harmful), and the braces { }
are not needed for a single simple command, all that makes this a better version:
if [ "$a" = 1 ]; then echo yes; fi
Or, if you choose to use bash/ksh/zsh [[ ]]
:
if [[ $a == 1 ]]; then echo yes; fi
And, lastly, the test with either =
or ==
is a string comparison, not numerical, so +1
would not be equal to 1
even if they are in value. To test numerically, you could use -eq
.
[
is a command in Bash, just like any of the other commands such as if
, while
, etc. You can see this if you double check the man page:
$ man [
NAME
bash, :, ., [, alias, bg, bind, break, builtin, caller, cd, command, .....
You can also tell it's a real command with this example:
$ type -a [
[ is a shell builtin
[ is /usr/bin/[
The first result is the builtin version of [
that's part of Bash. The second is the version of [
that's included with the GNU coreutils.
On Fedora you can see what RPM it's a part of:
$ rpm -qf /usr/bin/[
coreutils-8.5-7.fc14.x86_64
Given this you need to make sure that there are spaces around any commands so that they get parsed correctly.
Doing this:
$ if [$a == 1] ...
Would be identical to this:
$ lsblah
bash: lsblah: command not found...
The ls
command cannot be parsed correctly because it isn't buffered with spaces so that it's parse-able.
man [
is extremely informative. It's also interesting to know that [
is a command and has its own man page...
– Honey
Mar 22 '20 at 23:23
if [ "$a" = 1 ]; then echo yes; fi
or
if test "$a" -eq 1 ; then echo yes; fi
or
if /usr/bin/test "$a" -eq 1;then echo yes;fi
The shell will cut the command line to test at the semi-colon (and then add the arguments to test's command-line - argc/argv if it wasn't a built-in)
But this doesn't work:
if test "$a"-eq 1; then echo yes; fi
Where should the shell split the arguments to test ? so it wont split the string '+1-eq 1'
That test is a separate program becomes obvious if doing this:
sh:~$ LANG=C sh -c 'a=+1 ; if test "$a"-eq 1 ; then echo yes ; fi'
sh: 1: test: +1-eq: unexpected operator
compared with this:
sh:~$ LANG=C sh -c 'a=+1 ; if /usr/bin/test "$a"-eq 1;then echo yes;fi'
/usr/bin/test: missing argument after '1'
Hmm, different error messages for the same arguments to test...
[ $a == 1 ]
instead of[$a == 1]
. Of course, it is recommended to use a separate equals sign=
rather than a double sign==
. The two signs represent "bashism" (applicable only in some Shell). More info about double or single equal signs, for example, here: https://unix.stackexchange.com/questions/72039/whats-the-difference-between-single-and-double-equal-signs-in-shell-compari And also for POSIX syntax, it is better to use the-eq
comparison operator instead of=
. – s3n0 Mar 23 '20 at 09:38