Error de sintaxis cerca del token inesperado `fi`

17

No necesariamente quiero la respuesta, pero si alguien pudiera señalarme literatura o ejemplos. Me gustaría resolverlo.

Cuando ejecuto el script recibo un error:

Error de sintaxis cerca de token inesperado fi

He deducido que mi problema está en mi ifdeclaración al hacer mis ifcomentarios de declaraciones y agregar lo echo "$NAME"que muestra los nombres en el /etc/.

Cuando hago cambios, retire el #de ify fiy añadir #a wc -c "$NAME", recibo el error de sintaxis que se enumeran más arriba. He agregado ;entre ]entonces. También me he movido thena la siguiente línea sin resolución.

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

     if [ -r "$NAME" -af "$NAME" ] then
          wc -c "$NAME"
     fi
done
Christina A Guzman
fuente
9
Siempre que tenga un error de sintaxis de shell, un buen primer paso es cortar y pegar su código en shellcheck.net y corregir los errores que identifica. Si tiene problemas para comprender sus mensajes, venga aquí y pregunte.
John1024
2
¿Qué se -afsupone que debe hacer?
ilkkachu
Gracias por ese sitio @ John1024 que era más útil, he marcado como favorito para futuras referencias.
Christina A Guzman
1
@ChristinaAGuzman En tal caso -aes redundante porque la condición ya está incluido dentro -f. --- De todos modos múltiples condiciones dentro [ ](este comando también está disponible como test) que se unió a la utilización de operadores lógicos, como -a(y) o -o(o), sino como se sugirió en la respuesta de abajo es mejor uso múltiple [ ]( test) y unirse a los comandos utilizando operadores de shell como &&o ||.
pabouk
2
Christina, como se señaló en @ John1024, shellcheck.net muestra muy claramente alguna sintaxis o incluso errores más profundos (como lo hace la pelusa para el código C). También recomiendo una lectura obligada: mywiki.wooledge.org/BashPitfallsléalo al menos una vez!) Y mywiki.wooledge.org/BashFAQ y mywiki.wooledge.org/BashGuide también son buenos para leer.
Olivier Dulac

Respuestas:

46

Palabras claves como if, then, else, fi, for, casey así sucesivamente necesidad de estar en un lugar donde la cáscara espera un nombre de comando. De lo contrario, se tratan como palabras ordinarias. Por ejemplo,

echo if

solo imprime if, no comienza una instrucción condicional.

Por lo tanto, en la línea

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

la palabra thenes un argumento del comando [(del cual se quejaría si alguna vez llegara a ejecutarse). El shell sigue buscando el then, y encuentra una fiposición de comando. Como hay una ifque todavía está buscando su then, fies inesperado, hay un error de sintaxis.

Debe poner un terminador de comando antes thenpara que se reconozca como una palabra clave. El terminador más común de comandos es un salto de línea, pero antes then, es común el uso de un punto y coma (que tiene exactamente el mismo significado que un salto de línea).

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

o

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

Una vez que solucione eso, obtendrá otro error del comando [porque no lo comprende -af. Probablemente quisiste decir

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

Aunque los comandos de prueba parecen opciones, no puede agruparlos así. Son operadores del [comando y deben ser cada una una palabra separada (como do [y ]).

Por cierto, aunque [ -r "$NAME" -a -f "$NAME" ]funciona, recomiendo escribir

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

o

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

Es mejor mantener los [ … ]condicionales simples porque el [comando no puede distinguir a los operadores del operando fácilmente. Si $NAMEse parece a un operador y aparece en una posición donde el operador es válido, se pudo analizar como un operador. Esto no sucederá en los casos simples visto en esta respuesta, pero los casos más complejos puede ser arriesgado. Escribir esto con llamadas separadas [y usar los operadores lógicos del shell evita este problema.

La segunda sintaxis utiliza el [[ … ]]constructo condicional que existe en bash (y ksh y zsh, pero no sh llano). Esta construcción se sintaxis especial, mientras [se analiza como cualquier otro comando, así que puede usar cosas como &&el interior y que no es necesario que las variables de cotización, salvo en los argumentos de algunos operadores de cadena ( =, ==, !=, =~) (ver ¿Cuándo es necesario citar doble ? para más detalles).

Gilles 'SO- deja de ser malvado'
fuente
Tenga if [[ 1 ]] then [[ 2 ]] fien cuenta que funciona en ksh, pdksh y zsh. if(:)then(:)fiFunciona en todos los depósitos.
Stéphane Chazelas
12

Vea lo que ha cambiado de la siguiente manera

si [-r "$ NOMBRE" -a -f "$ name"] ; luego
# ^^^^^ ^
     wc -c "$ NOMBRE"
fi

Si desea eliminar todos los comandos de si el bloque, que al menos necesidad de añadir dos puntos en ella, como

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

o una versión de línea

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

Bruce
fuente
2

Otros ya lo señalaron, pero si está buscando una referencia oficial, entonces RTM

si la lista; luego lista; [lista elif; luego lista; ] ... [lista de los demás;] fi

Se ejecuta el caso de la lista. Si su estado de salida es cero, se ejecuta la lista. De lo contrario, cada lista elif se ejecuta a su vez, y si su estado de salida es cero, se ejecuta el thenlist correspondiente y finaliza el comando. De lo contrario, se ejecuta la lista else, si está presente. El estado de salida es el estado de salida del último comando ejecutado, o cero si no hay condición probada verdadera.

Te estás perdiendo el ;

Y la sintaxis para listse describe enman test

Kashyap
fuente