Shell Script - синтаксическая ошибка рядом с неожиданным токеном else


15

С помощью следующего сценария оболочки, почему я получаю ошибки

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


Вы можете отредактировать строку «копировать из ....», так как она может показывать то, что вы не хотите показывать. (Тем не менее, я надеюсь, что это уже измененная информация, так как они были бы очень плохими в плане безопасности)
Оливье Дюлак

1
@OlivierDulac Если вы ссылаетесь на имя пользователя и пароль в этой строке, то они известны всем пользователям базы данных Oracle. Это распространено и хорошо известно с самого начала базы данных Oracle.
Jåcob

@OlivierDulac Добро пожаловать, немного информации об этом dba-oracle.com/t_scott_tiger.htm
Jåcob

Ответы:


25

Вы должны прекратить условие, ifкак это:

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

или вот так:

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

Примечание: вы также должны поставить пробелы после [и до ].

Причиной ;переноса строки или является то, что условная часть ifоператора является просто командой. Любая команда любой длины, если быть точным. Оболочка выполняет эту команду, проверяет состояние завершения команды и затем решает, выполнять ли thenчасть или elseчасть.

Поскольку команда может быть любой длины, для обозначения конца условной части необходим маркер. Это ;или новая строка с последующим then.

Причина пробелов в [том, что [это команда. Обычно это встроенная оболочка. Оболочка выполняет команду [с остальными параметрами, включая ]обязательный последний параметр. Если вы не поставите пробел после того, [как оболочка попытается выполнить [whateverкак команду и завершится ошибкой.

Причина для пространства до того ]похожа. Потому что в противном случае он не будет распознаваться как собственный параметр.


Это было на месте, однако теперь я получаю test.sh: line 6: [: missing ] '`
Jåcob

@lesmana. Хороший способ сначала дать неправильный ответ, затем продолжить редактирование, прежде чем кто-то другой предоставит правильный ответ. Пожалуйста, попробуйте дать правильный ответ с первого раза.
Валентин Байрами

1
Я не считаю свой первый ответ неправильным. На самом деле, это было «пятно на». Это просто не решило всех проблем в вопросе.
Lesmana

if это синтаксис, это не обычная команда. Это зарезервированное слово. В отличие от многих других языков программирования, оболочка не распознает зарезервированные слова везде, только когда они являются первым словом команды (с некоторыми тонкостями).
Жиль "ТАК - перестань быть злым"

Благодарю за разъяснение. Я знаю, что ifэто синтаксис. Я пытался сообщить, что условие условие ifне ограничено определенной формой по синтаксису. Я отредактировал текст. Надеюсь, теперь стало понятнее.
Lesmana

5

Вы можете легко проверить свои сценарии оболочки, используя ShellCheck онлайн (также доступный как самостоятельный инструмент).

В этом случае он укажет, что оператору if нужны пробелы после [и до ], и что вам нужно ;(или символ новой строки) перед thenтой же строкой.

Когда вы исправите это, он будет рассказывать вам, что USER_NAMEон используется без какой-либо инициализации. Это потому, что у вас также есть user_nameпеременная (регистр имеет значение). То же самое относится и к PASSи pass.

Он также говорит, что вы должны использовать, read -rчтобы остановить readискажения \(например, это может быть важно для паролей), и что вы должны ставить в кавычки переменные при вызове, sqlplusчтобы предотвратить случайное выполнение оболочкой слежения за именами файлов и разделения слов (опять же, это важно, если пароль, например, содержит символы, такие как *или пробелы).

Отступ кода также сделает его более читабельным:

#!/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

Здесь я также сделал возможным использование паролей с начальными или конечными пробелами, временно установив IFSпустую строку для чтения пароля read.

Логика также была изменена, чтобы выручить, если $ORACLE_SID/ $sidесть Test. Это позволяет избежать основной рабочей части скрипта в ifветке.


Обратите внимание, что это if ([ x = x ]) then (echo yes) fiтакже работает.
Стефан Шазелас

@ StéphaneChazelas Ах, да. И это может быть интересно с точки зрения программы, генерирующей шелл-код, но это не то, как обычно пишут ifоператоры с [ ... ]... :-)
Кусалананда

2

При написании shвы хотели бы

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

При написании bash

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

Обратите внимание на пробелы, пожалуйста. Между [[первым оператором должен быть пробел .

Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.