Errore di sintassi vicino al token imprevisto `fi`


17

Non voglio necessariamente la risposta, ma se qualcuno potesse indicarmi della letteratura o degli esempi. Vorrei capirlo.

Quando eseguo lo script ricevo un errore:

Errore di sintassi vicino a token imprevisto fi

Ho dedotto che il mio problema è nella mia ifdichiarazione facendo ifcommenti e aggiungendo quelli echo "$NAME"che visualizzano i nomi in /etc/.

Quando apporto modifiche, rimuovo #da ife fie aggiungo #a wc -c "$NAME", ricevo l'errore di sintassi che ho elencato sopra. Ho aggiunto ;tra ]allora. Mi sono anche spostato thenalla riga successiva senza risoluzione.

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

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

9
Ogni volta che si verifica un errore di sintassi della shell, un buon primo passo è tagliare e incollare il codice in shellcheck.net e correggere gli errori che identifica. Se hai problemi a comprenderne i messaggi, vieni qui e chiedi.
Giovanni 1024

2
Cosa -afdovrebbe fare?
ilkkachu,

Grazie per quel sito @ John1024 è stato molto utile, l'ho aggiunto ai segnalibri per riferimento futuro.
Christina A Guzman,

1
@ChristinaAGuzman In tal caso -aè ridondante perché la condizione è già inclusa all'interno -f. --- Comunque più condizioni all'interno [ ](questo comando è disponibile anche come test) devono essere unite usando operatori logici come -a(e) o -o(o) ma come è stato suggerito nella risposta sotto è meglio usare più comandi [ ]( test) e unire usando operatori di shell come &&o ||.
pabouk,

2
Christina, come sottolineato @ John1024, shellcheck.net mostra in modo molto chiaro una sintassi o errori anche più profondi (come fa lint per il codice C). Consiglio anche di leggere: mywiki.wooledge.org/BashPitfalls (leggilo almeno una volta!) E mywiki.wooledge.org/BashFAQ e mywiki.wooledge.org/BashGuide sono anch'essi buoni da leggere.
Olivier Dulac l'

Risposte:


46

Parole chiave come if, then, else, fi, for, casee così via necessità di essere in un luogo in cui il guscio si aspetta un nome di comando. Altrimenti sono trattati come parole ordinarie. Per esempio,

echo if

stampa if, non avvia un'istruzione condizionale.

Quindi, in linea

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

la parola thenè un argomento del comando [(di cui si lamenterebbe se dovesse mai essere eseguito). La shell continua a cercare il then, e trova una fiposizione di comando. Dal momento che c'è un oggetto ifche sta ancora cercando then, fiè inaspettato, c'è un errore di sintassi.

È necessario inserire prima un terminatore di comando in thenmodo che venga riconosciuto come parola chiave. Il terminatore di comando più comune è un'interruzione di riga, ma prima thenè comune utilizzare un punto e virgola (che ha esattamente lo stesso significato di un'interruzione di riga).

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

o

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

Una volta risolto il problema, otterrai un altro errore dal comando [perché non capisce -af. Presumibilmente intendevi

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

Sebbene i comandi di test appaiano come opzioni, non è possibile raggrupparli in questo modo. Sono operatori del [comando e devono essere ciascuno una parola separata (come do [e ]).

A proposito, anche se [ -r "$NAME" -a -f "$NAME" ]funziona, consiglio di scrivere neanche

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

o

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

È meglio mantenere [ … ] semplici i condizionali perché il [comando non è in grado di distinguere facilmente gli operatori dall'operando. Se $NAMEappare come un operatore e appare in una posizione in cui l'operatore è valido, potrebbe essere analizzato come operatore. Ciò non accadrà nei casi semplici visti in questa risposta, ma casi più complessi possono essere rischiosi. Scrivere questo con chiamate separate [e usare gli operatori logici della shell evita questo problema.

La seconda sintassi usa il [[ … ]]costrutto condizionale che esiste in bash (e ksh e zsh, ma non in sh). Questo costrutto è sintassi speciale, mentre [viene analizzato come qualsiasi altro comando, in tal modo è possibile utilizzare le cose come &&dentro e non è necessario per le variabili di citazione tranne in argomenti di alcuni operatori di stringa ( =, ==, !=, =~) (vedi Quando è doppi apici necessaria ? per i dettagli).


Nota che if [[ 1 ]] then [[ 2 ]] fifunziona in ksh, pdksh e zsh. if(:)then(:)fifunziona in tutte le conchiglie.
Stéphane Chazelas,

12

Guarda cosa è cambiato come segue

if [-r "$ NAME" -a -f "$ NAME"] ; poi
# ^^^^^ ^
     wc -c "$ NAME"
fi

Se vuoi rimuovere tutti i comandi in if block, almeno devi aggiungere due punti in esso, come

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

o versione a una riga

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


2

Altri hanno già sottolineato, ma se stai cercando un riferimento ufficiale, allora RTM

se elenco; quindi elencare; [elenco elif; quindi elencare; ] ... [altro elenco;] fi

L'elenco if viene eseguito. Se il suo stato di uscita è zero, l'elenco allora viene eseguito. Altrimenti, ogni elenco elif viene eseguito a sua volta e se il suo stato di uscita è zero, viene eseguito l'elenco corrispondente corrispondente e il comando viene completato. Altrimenti, viene eseguito l'elenco else, se presente. Lo stato di uscita è lo stato di uscita dell'ultimo comando eseguito o zero se nessuna condizione è stata verificata vera.

Ti manca il ;

E la sintassi per listè descritta inman test

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.