Shell脚本-意外令牌'else'附近的语法错误


15

使用以下shell脚本,为什么我会出错

syntax error near unexpected token `else'

Shell脚本

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


您可能需要编辑“从...复制”行,因为该行当前正在显示您不想显示的内容。(不过,我确实希望这些信息已经被修改,因为它们在安全性方面确实很差)
Olivier Dulac

1
@OlivierDulac如果您在该行中引用用户名和密码,则所有Oracle数据库用户都知道这些用户名和密码。自Oracle数据库开始以来,它是常见且众所周知的。
2013年

@OlivierDulac欢迎您,关于这个一些信息dba-oracle.com/t_scott_tiger.htm
雅各布

Answers:


25

您必须终止这样的条件if

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

或像这样:

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

注意:您还必须在[之前和之后放置空格]

;或换行符的原因是该if语句的条件部分只是一个命令。任何长度的精确命令。外壳程序执行该命令,检查命令的退出状态,然后决定执行then零件还是else零件。

由于命令可以是任意长度,因此需要有一个标记来标记条件部分的结尾。即是;或换行符,其后是then

后面留空格的原因[是因为[是命令。通常是外壳的内置。Shell执行命令[,其余命令作为参数,包括]作为必需的最后一个参数。如果您[在外壳程序之后不加空格,它将尝试[whatever作为命令执行并失败。

之前留出空间的原因与此]类似。因为否则它将不会被识别为其自身的参数。


这是现货上,但是现在我越来越test.sh: line 6: [: missing ]'`
雅各布

@lesmana。先提供错误答案的好方法,然后在他人提供正确答案之前继续进行编辑。请在第一时间尝试提供正确答案。
Valentin Bajrami

1
我不认为我的第一个答案是错误的。实际上,这是“现场”。它只是不能解决问题中的所有问题。
lesmana

if 语法,这不是普通的命令。这是保留字。与许多其他编程语言不同,shell不会在所有地方都识别保留字,只有当它们是命令的第一个字(有一些微妙之处)时才识别。
吉尔(Gilles)'所以

感谢您的澄清。我知道这if是语法。我试图传达的是,条件的条件部分if不受语法约束。我已经编辑了文字。我希望现在更加清楚。
lesmana

5

您可以轻松地使用ShellCheck在线检查Shell脚本(也可以作为独立工具使用)。

在这种情况下,它将指出if语句在after [和before之前需要空格,并且同一行上的if 之前]需要一个;(或换行符)then

修复该问题后,它将继续告诉您USER_NAME已使用它而未初始化为任何东西。这是因为您也有一个user_name变量(大小写有关)。同样是真正的PASSpass

它还告诉您使用read -r来停止read改写\(例如,对于密码来说可能很重要),并且在调用时应双引号,sqlplus以防止Shell意外进行文件名混淆和单词拆分(同样,如果例如,密码包含文件名字符,例如*或)。

缩进代码也将使其更具可读性:

#!/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也可以。
斯特凡·查泽拉斯18'Feb

@StéphaneChazelas啊,是的。从生成shell代码的程序的角度来看,这可能很有趣,但通常不是这样写的if与报表[ ... ]... :-)
Kusalananda

2

写作时sh你想要

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

写作时 bash

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

请注意空间。[[第一个运算符与第一个运算符之间必须有一个空格。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.