Shell Script: error de sintaxis cerca del token inesperado `else '

15

Con el siguiente script de shell, ¿por qué recibo errores?

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
Jåcob
fuente
es posible que desee editar la línea "copiar de ...", ya que actualmente puede mostrar algo que no desea mostrar. (Sin embargo, espero que ya sean infos modificados, ya que serían muy pobres en seguridad)
Olivier Dulac
1
@OlivierDulac Si se refiere al nombre de usuario y contraseña en esa línea, todos los usuarios de la base de datos Oracle los conocen. Es común y bien conocido desde el comienzo de la base de datos Oracle.
Jåcob
@OlivierDulac De nada, alguna información sobre este dba-oracle.com/t_scott_tiger.htm
Jåcob

Respuestas:

25

Tienes que terminar la condición de ifesta manera:

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

o así:

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

Nota: también debes poner espacios después [y antes ].

La razón del ;salto de línea o es que la parte de condición de la ifdeclaración es solo un comando. Cualquier comando de cualquier longitud para ser precisos. El shell ejecuta ese comando, examina el estado de salida del comando y luego decide si ejecutar la thenparte o la elseparte.

Debido a que el comando puede tener cualquier longitud, debe haber un marcador para marcar el final de la parte de la condición. Esa es la ;o la nueva línea, seguida de then.

La razón de los espacios después [es porque [es un comando. Por lo general, una construcción de la cáscara. El shell ejecuta el comando [con el resto como parámetros, incluido el ]último parámetro obligatorio. Si no coloca un espacio después, [el shell intentará ejecutarse [whatevercomo comando y fallará.

La razón del espacio antes del ]es similar. Porque de lo contrario no se reconocerá como un parámetro propio.

lesmana
fuente
Eso fue test.sh: line 6: [: missing
perfecto
@lesmana. Una buena manera de proporcionar una respuesta incorrecta primero, luego siga editando antes de que otra persona proporcione la respuesta correcta. Intente proporcionar la respuesta correcta la primera vez.
Valentin Bajrami
1
No considero mi primera respuesta como incorrecta. De hecho, fue "perfecto". Simplemente no resolvió todos los problemas en la pregunta.
lesmana
if es sintaxis, no es un comando ordinario. Es una palabra reservada. A diferencia de muchos otros lenguajes de programación, el shell no reconoce palabras reservadas en todas partes, solo cuando son la primera palabra de un comando (con algunas sutilezas).
Gilles 'SO- deja de ser malvado'
Gracias por la aclaración. Soy consciente de que ifes la sintaxis. Estaba tratando de comunicar que la parte de la condición ifno está limitada a una determinada forma por la sintaxis. He editado el texto. Espero que sea más claro ahora.
lesmana
5

Puede verificar fácilmente sus scripts de shell utilizando ShellCheck en línea (también disponible como una herramienta independiente).

En este caso, señalará que la instrucción if necesita espacios, después [y antes ], y que necesita un ;(o una nueva línea) antes del thenen la misma línea.

Cuando haya solucionado eso, continuará diciéndole que USER_NAMEse utiliza sin inicializarse a nada. Esto se debe a que también tiene una user_namevariable (los casos son importantes). Lo mismo es cierto para PASSy pass.

También le indica que use read -rpara evitar la readmanipulación \(podría ser importante para las contraseñas, por ejemplo), y que debe citar las variables al llamar sqlpluspara evitar que el intérprete accidentalmente se bloquee el nombre del archivo y se divida la palabra (de nuevo, esto es importante si la contraseña, por ejemplo, contiene caracteres globales de archivos como *espacios).

La sangría del código también lo hará más legible:

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

Aquí también he hecho posible el uso de contraseñas con caracteres de espacio iniciales o finales al configurar temporalmente IFSuna cadena vacía para la lectura de la contraseña read.

La lógica también se cambió para rescatar si $ORACLE_SID/ $sides Test. Esto evita tener la parte operativa principal del script en una iframa.

Kusalananda
fuente
Tenga en cuenta que if ([ x = x ]) then (echo yes) fitambién funciona.
Stéphane Chazelas
@ StéphaneChazelas Ah, sí. Y eso puede ser interesante desde el punto de vista de un programa que genera código de shell, pero no es así como uno suele escribir ifdeclaraciones con [ ... ]... :-)
Kusalananda
2

Cuando escribas shte gustaría

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

Cuando se escribe bash

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

Cuidado con los espacios por favor. Debe haber un espacio entre [[y el primer operador.

Valentin Bajrami
fuente