I don't necessarily want the answer but if someone could point me to some literature or examples. I would like to figure it out.
When I run the script I receive an error:
Syntax error near unexpected token
fi
I have deduced that my problem is in my if
statement by making my if
statements comments and adding echo "$NAME"
which displays the names in the /etc/
.
When I make changes, remove the #
from if
and fi
and add #
to wc -c "$NAME"
, I receive the syntax error I listed above. I have added ;
between ]
then. I have also moved then
to the next line with no resolution.
#!/bin/bash
for NAME in /etc/*
do
if [ -r "$NAME" -af "$NAME" ] then
wc -c "$NAME"
fi
done
Best Answer
Keywords like
if
,then
,else
,fi
,for
,case
and so on need to be in a place where the shell expects a command name. Otherwise they are treated as ordinary words. For example,just prints
if
, it doesn't start a conditional instruction.Thus, in the line
the word
then
is an argument of the command[
(which it would complain about if it ever got to run). The shell keeps looking for thethen
, and finds afi
in command position. Since there's anif
that's still looking for itsthen
, thefi
is unexpected, there's a syntax error.You need to put a command terminator before
then
so that it's recognized as a keyword. The most common command terminator is a line break, but beforethen
, it's common to use a semicolon (which has exactly the same meaning as a line break).or
Once you fix that you'll get another error from the command
[
because it doesn't understand-af
. You presumably meantAlthough the test commands look like options, you can't bundle them like this. They're operators of the
[
command and they need to each be a separate word (as do[
and]
).By the way, although
[ -r "$NAME" -a -f "$NAME" ]
works, I recommend writing eitheror
It's best to keep
[ … ]
conditionals simple because the[
command can't distinguish operators from operand easily. If$NAME
looks like an operator and appears in a position where the operator is valid, it could be parsed as an operator. This won't happen in the simple cases seen in this answer, but more complex cases can be risky. Writing this with separate calls to[
and using the shell's logical operators avoids this problem.The second syntax uses the
[[ … ]]
conditional construct which exists in bash (and ksh and zsh, but not plain sh). This construct is special syntax, whereas[
is parsed like any other command, thus you can use things like&&
inside and you don't need to quote variables except in arguments to some string operators (=
,==
,!=
,=~
) (see When is double-quoting necessary? for details).