Shell Script - erro de sintaxe próximo ao token inesperado `else '

15

Com o seguinte script shell, por que estou recebendo erros

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
fonte
convém editar a linha "copiar de ....", pois ela pode estar mostrando algo que você não deseja mostrar no momento. (No entanto, eu espero que aqueles que já estão informações sobre modificados, uma vez que seria realmente pobre de segurança sábio)
Olivier Dulac
1
@OlivierDulac Se você estiver se referindo ao nome de usuário e senha nessa linha, eles serão conhecidos por todos os usuários do banco de dados Oracle. É comum e conhecido desde o início do banco de dados Oracle.
precisa saber é
@OlivierDulac Você é bem-vindo, algumas informações sobre este dba-oracle.com/t_scott_tiger.htm
Jacob

Respostas:

25

Você deve encerrar a condição ifcomo esta:

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

ou assim:

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

Nota: você também precisa colocar espaços [antes e depois ].

A razão para a ;quebra de linha ou é que a parte da condição da ifinstrução é apenas um comando. Qualquer comando de qualquer comprimento para ser preciso. O shell executa esse comando, examina o status de saída do comando e decide se deve executar a thenparte ou a elseparte.

Como o comando pode ter qualquer comprimento, é necessário haver um marcador para marcar o final da parte da condição. Essa é a ;ou a nova linha, seguida por then.

A razão para os espaços depois [é porque [é um comando. Geralmente um builtin do shell. O shell executa o comando [com o restante como parâmetros, incluindo o ]último parâmetro como obrigatório. Se você não colocar um espaço após [o shell, ele tentará executar [whatevercomo comando e falhará.

A razão do espaço antes do ]é semelhante. Porque, caso contrário, não será reconhecido como um parâmetro próprio.

lesmana
fonte
Isso foi test.sh: line 6: [: missing
imediato
@lesmana. É uma boa maneira de fornecer uma resposta errada primeiro, depois continue editando antes que outra pessoa forneça a resposta correta. Tente fornecer a resposta correta na primeira vez.
Valentin Bajrami
1
Não considero minha primeira resposta errada. Na verdade, estava "no local". Apenas não resolveu todos os problemas da questão.
Lesmana
if é sintaxe, não é um comando comum. É uma palavra reservada. Ao contrário de muitas outras linguagens de programação, o shell não reconhece palavras reservadas em todos os lugares, apenas quando elas são a primeira palavra de um comando (com algumas sutilezas).
Gilles 'SO- stop be evil' (
Obrigado pelo esclarecimento. Estou ciente de que ifé sintaxe. Eu estava tentando comunicar que a parte da condição do ifnão é restrita a uma determinada forma pela sintaxe. Eu editei o texto. Espero que esteja mais claro agora.
Lesmana
5

Você pode verificar facilmente seus scripts de shell usando o ShellCheck online (também disponível como uma ferramenta independente).

Nesse caso, ele indicará que a instrução if precisa de espaços, depois [e antes ], e que você precisa de uma ;(ou uma nova linha) antes thenda mesma linha.

Quando você tiver corrigido isso, ele continuará dizendo que USER_NAMEé usado sem ser inicializado em nada. Isso ocorre porque você também tem uma user_namevariável (o caso importa). O mesmo vale para PASSe pass.

Ele também diz para você usar read -rpara parar readde manipular \(pode ser importante para senhas, por exemplo), e que você deve citar duas vezes as variáveis ​​ao chamar sqlpluspara impedir que o shell acidentalmente faça globbing e divisão de palavras de nomes de arquivos (novamente isso é importante se a senha, por exemplo, contém caracteres ocultos de arquivos como *espaços ou espaços).

Recuar o código também o tornará mais legível:

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

Aqui também possibilitei o uso de senhas com caracteres de espaço à esquerda ou à direita, configurando temporariamente IFSuma string vazia para a leitura da senha read.

A lógica também foi alterada para resgatar se $ORACLE_SID/ $sidé Test. Isso evita ter a parte operacional principal do script em uma iframificação.

Kusalananda
fonte
Observe que if ([ x = x ]) then (echo yes) fitambém funciona.
Stéphane Chazelas
@ StéphaneChazelas Ah, sim. E isso pode ser interessante do ponto de vista de um programa que gera código shell, mas não é como se costuma escrever ifdeclarações com [ ... ]... :-)
Kusalananda
2

Ao escrever, shvocê gostaria

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

Ao escrever bash

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

Cuide dos espaços, por favor. Deve haver um espaço entre [[e o primeiro operador.

Valentin Bajrami
fonte