14

With the following shell script, why I am getting errors

syntax error near unexpected token `else'

Shell Script

echo "please enter username"
read user_name
echo "please enter password"
read -s pass
echo ${ORACLE_SID}
SID=${ORACLE_SID}
if ["${ORACLE_SID}" != 'Test'] then
sqlplus -s -l $USER_NAME/$PASS@$SID <<EOF
copy from scott/tiger@orcl insert EMP using select * from EMP
exit
EOF
else
echo "Cannot copy"
fi
  • paste.ubuntu.com/6013802 – Rahul Patil Aug 22 '13 at 12:04
  • you may want to edit the line "copy from ...." as it may be currently showing something you don't want to show. (However, I do hope those are already modified infos, as they would be really poor security wise) – Olivier Dulac Aug 22 '13 at 16:24
  • 1
    @OlivierDulac If you are referring to username and password in that line then those are known to all Oracle database users. It is common and well known since the beginning of Oracle database. – Jåcob Aug 23 '13 at 6:36
  • @OlivierDulac You are welcome, some info about this dba-oracle.com/t_scott_tiger.htm – Jåcob Aug 23 '13 at 8:06
23

You have to terminate the condition of if like this:

if [ "${ORACLE_SID}" != 'Test' ]; then

or like this:

if [ "${ORACLE_SID}" != 'Test' ]
then

Note: you also have to put spaces after [ and before ].

The reason for the ; or linebreak is that the condition part of the if statement is just a command. Any command of any length to be precise. The shell executes that command, examines the exit status of the command, and then decides whether to execute the then part or the else part.

Because the command can be of any length there needs to be a marker to mark the end of the condition part. That is the ; or the newline, followed by then.

The reason for the spaces after [ is because [ is a command. Usually a builtin of the shell. The shell executes the command [ with the rest as parameters, including the ] as mandatory last parameter. If you do not put a space after [ the shell will try to execute [whatever as command and fail.

The reason for space before the ] is similar. Because otherwise it will not be recognized as a parameter of its own.

  • That was spot on, however now I am getting test.sh: line 6: [: missing ]'` – Jåcob Aug 22 '13 at 12:00
  • @lesmana. A good way to provide a wrong answer first, then keep editing before someone else provides the correct answer. Please try to provide the correct answer the first time. – Valentin Bajrami Aug 22 '13 at 12:14
  • 1
    I do not consider my first answer as wrong. In fact, it was "spot on". It just did not solve all the problems in the question. – lesmana Aug 22 '13 at 12:39
  • if is syntax, it isn't an ordinary command. It's a reserved word. Unlike many other programming languages, the shell doesn't recognize reserved words everywhere, only when they're the first word of a command (with a few subtleties). – Gilles Aug 22 '13 at 22:02
  • Thanks for the clarification. I am aware that if is syntax. I was trying to communicate that the condition part of the if is not constrained to a certain form by syntax. I have edited the text. I hope it is clearer now. – lesmana Aug 22 '13 at 22:40
5

You may easily check your shell scripts using ShellCheck online (also available as a standalone tool).

In this case, it will point out that the if-statement needs spaces, after [ and before ], and that you need a ; (or a newline) before the then on the same line.

When you've fixed that, it will go on to tell you that USER_NAME is used without being initialized to anything. This is because you also have a user_name variable (case matters). The same is true for PASS and pass.

It also tells you to use read -r to stop read from mangling \ (could be important for passwords, for example), and that you should double quote the variables when calling sqlplus to prevent the shell from accidentally doing file name globbing and word splitting (again this is important if the password, for example, contains file globbing characters like *, or spaces).

Indenting the code will make it more readable too:

#!/bin/bash

read -r -p 'please enter username: ' user_name
IFS= read -rs -p 'please enter password: ' pass

printf 'ORACLE_SID = %s\n' "$ORACLE_SID"
sid=$ORACLE_SID

if [ "$sid" = 'Test' ]; then
    echo 'Cannot copy' >&2
    exit 1
fi

sqlplus -s -l "$user_name/$pass@$sid" <<'SQL_END'
copy from scott/tiger@orcl insert EMP using select * from EMP
exit
SQL_END

Here I've also made it possible to use passwords with leading or trailing space characters by temporarily setting IFS to an empty string for the password reading read.

The logic was also changed to bail out if $ORACLE_SID/$sid is Test. This avoids having the main operational part of the script in an if branch.

  • Note that if ([ x = x ]) then (echo yes) fi also works. – Stéphane Chazelas Feb 25 '18 at 10:23
  • @StéphaneChazelas Ah, yes. And that may be interesting form the point of view of a program generating shell code, but it's not how one usually writes if statements with [ ... ]... :-) – Kusalananda Feb 25 '18 at 10:26
2

When writing sh you'd want

if [ "$ORACLE_SID" != "Test" ]
then
  ...
fi

When writing bash

if [[ "$ORACLE_SID" != "Test" ]]
then
  ...
fi

Mind the spaces please. There must be a space between [[ and first operator.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.