Bash || within if []; block
I have code matching:
if [ $LAST_MODIFIED -lt 3600 || ! -f "$i" ]; then
wget $WGET_OPTS $BASE$i
LAST_MODIFIED=`echo "\`date +%s\` - \`stat -c %Y $i\`" | bc`
if [ $LAST_MODIFIED -lt 500 ]; then
$FILES_MODIFIED++
fi
fi
$i
is defined via
for i in `/bin/grep ".gz" index.html | awk -F\" '{pr开发者_Python百科int $2}'`
however, bash tells me
[: missing `]'
and
-f: command not found
Why?
You should either use [[ ... ]]
instead of [ ... ]
or use -o
instead of ||
.
if [[ $LAST_MODIFIED -lt 3600 || ! -f "$i" ]]; then
or:
if [ $LAST_MODIFIED -lt 3600 -o ! -f "$i" ]; then
See here: http://www.ibm.com/developerworks/library/l-bash-test.html
Should be
if [ $LAST_MODIFIED -lt 3600 ] || ! [ -f "$i" ]; then
[
(and !
) are shell built-ins. They are not part of the syntax for if
.
Try to rewrite your if as
if [ cond a ] || [ cond b ]; then
...
fi
[
is an actual builtin command, that requires ]
as it's last argument.
However your syntax makes the last argument to [
"3600
", and then starts a new command..
Try making the command between the [
and ]
a single command.
Keep in mind that the bash [
built-in command must honor the syntax requirements of the external /bin/[
command (usually a link to /bin/test
) in order to maintain backward compatibility with the archaic versions of sh in which test
([
) was NOT internal to the shell.
In order to honor that level of compatibility the parser must treat || as a separator to a new command, thus terminating the [
command. When /bin/test
is called as [
(it checks its on argv[0]) then it requires the closing "]" as a parameter.
Use -o (or) in your test ([
) commands.
(Personally I think it's a bad idea do use the [
form of test
for exactly this reason. Novices will think of it as a syntactic feature ... a sort of conditional expression construct to the if
statement, expecting semantics which are not consistent with its implementation as command. So I teach it as test
even though I use it (sometimes) as [
because the practice is so widespread.
精彩评论