Erro de sintaxe próximo ao token inesperado `fi`


17

Não quero necessariamente a resposta, mas se alguém puder me apontar alguma literatura ou exemplos. Eu gostaria de descobrir isso.

Quando executo o script, recebo um erro:

Erro de sintaxe próximo token inesperado fi

Deduzi que meu problema está em minha ifdeclaração fazendo ifcomentários e adicionando echo "$NAME"quais exibem os nomes no /etc/.

Quando faço alterações, removo #de ife fiadiciono #a wc -c "$NAME", recebo o erro de sintaxe listado acima. Eu adicionei ;entre ]então. Também mudei thenpara a próxima linha sem resolução.

#!/bin/bash
for NAME in /etc/*
do

     if [ -r "$NAME" -af "$NAME" ] then
          wc -c "$NAME"
     fi
done

9
Sempre que houver um erro de sintaxe do shell, um bom primeiro passo é recortar e colar seu código no shellcheck.net e corrigir os erros que ele identifica. Se você tiver problemas para entender suas mensagens, venha aqui e pergunte.
John1024

2
O que isso -afdeveria fazer?
Ilkkachu

Obrigado por esse site @ John1024 foi mais útil, marquei-o para referência futura.
Christina A Guzman

1
@ChristinaAGuzman Nesse caso, -aé redundante porque a condição já está incluída -f. --- De qualquer forma, várias condições [ ](este comando também está disponível como test) precisam ser unidas usando operadores lógicos como -a(e) ou -o(ou), mas como foi sugerido na resposta abaixo, é melhor usar vários comandos [ ]( test) e associar usando operadores de shell como &&ou ||.
Pabouk

2
Christina, como apontado em John1024, shellcheck.net mostra muito claramente algumas sintaxes ou erros ainda mais profundos (como o lint faz para o código C). Eu também recomendo uma leitura obrigatória: é recomendável ler também mywiki.wooledge.org/BashPitfalls (leia pelo menos uma vez!) E mywiki.wooledge.org/BashFAQ e mywiki.wooledge.org/BashGuide .
Olivier Dulac

Respostas:


46

Palavras-chave como if, then, else, fi, for, casee assim por diante necessidade de estar em um lugar onde a Shell espera um nome de comando. Caso contrário, eles são tratados como palavras comuns. Por exemplo,

echo if

apenas imprime if, não inicia uma instrução condicional.

Assim, na linha

if [ -r "$NAME" -af "$NAME" ] then

a palavra thené um argumento do comando [(do qual reclamaria se alguma vez fosse executado). O shell continua procurando o thene encontra uma fiposição de comando. Como há um ifque ainda está procurando then, o fié inesperado, há um erro de sintaxe.

Você precisa colocar um terminador de comando antes thenpara que seja reconhecido como uma palavra-chave. O terminador de comando mais comum é uma quebra de linha, mas antes then, é comum usar um ponto-e-vírgula (que tem exatamente o mesmo significado que uma quebra de linha).

if [ -r "$NAME" -af "$NAME" ]; then

ou

if [ -r "$NAME" -af "$NAME" ]
then

Depois de corrigir isso, você receberá outro erro do comando [porque ele não entende -af. Você provavelmente quis dizer

if [ -r "$NAME" -a -f "$NAME" ]; then

Embora os comandos de teste pareçam opções, você não pode agrupá-los dessa maneira. Eles são operadores do [comando e precisam ser cada um uma palavra separada (como faça [e ]).

A propósito, embora [ -r "$NAME" -a -f "$NAME" ]funcione, eu recomendo escrever

[ -r "$NAME" ] && [ -f "$NAME" ]

ou

[[ -r $NAME && -f $NAME ]]

É melhor manter [ … ]condicionais simples, porque o [comando não pode distinguir operadores de operando facilmente. Se $NAMEparecer com um operador e aparecer em uma posição em que o operador é válido, ele poderá ser analisado como operador. Isso não acontecerá nos casos simples vistos nesta resposta, mas casos mais complexos podem ser arriscados. Escrever isso com chamadas separadas [e usar os operadores lógicos do shell evita esse problema.

A segunda sintaxe usa a [[ … ]]construção condicional existente no bash (e ksh e zsh, mas não sh simples). Esta construção é sintaxe especial, enquanto [é analisado como qualquer outro comando, assim você pode usar coisas como &&dentro e você não precisa variáveis cotação exceto em argumentos para alguns operadores de cordas ( =, ==, !=, =~) (ver Quando é colocar aspas necessário ? para detalhes).


Observe que if [[ 1 ]] then [[ 2 ]] fifunciona em ksh, pdksh e zsh. if(:)then(:)fifunciona em todas as conchas.
Stéphane Chazelas

12

Veja o que mudou da seguinte forma

se [-r "$ NAME" -a -f "$ NAME"] ; então
# ^^^^^ ^
     wc -c "$ NAME"
fi

Se você deseja remover todos os comandos no bloco if, é necessário adicionar pelo menos dois pontos, como

if [ -r "$NAME" -a -f "$NAME" ]; then
    :
fi

ou versão de uma linha

if [ -r "$NAME" -a -f "$NAME" ]; then :; fi


2

Outros já apontaram, mas se você estiver procurando por referência oficial, o RTM

se lista; então lista; [lista elif; então lista; ] ... [outra lista;] fi

A lista if é executada. Se o status de saída for zero, a lista então é executada. Caso contrário, cada lista elif será executada por sua vez, e se seu status de saída for zero, a lista then correspondente é executada e o comando é concluído. Caso contrário, a lista else é executada, se presente. O status de saída é o status de saída do último comando executado ou zero se nenhuma condição testada for verdadeira.

Está faltando o ;

E a sintaxe para listé descrita emman test

Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.