Errore di sintassi Bash quando "else" segue una clausola "then" vuota


36

Perché il seguente script non verrà eseguito, ma darebbe un errore di sintassi di else:

LOGS3_DIR=~/logs
if [ -d "$LOGS3_DIR" ]; then
 cd
 cd "$LOGS3_DIR"
 echo "$LOGS3_DIR"
 for filename in `find "." -mtime 1 -type f`
  do
  if lsof "$filename" > /dev/null
  then
    # file is open
  else
    echo "deleting $filename"
    rm "$filename"
  fi
 done
fi

Risposte:


23

Non utilizzare la sostituzione dei comandi sull'output difind . Qui, tutto può essere fatto con find:

find . -mtime 1 -type f ! -exec lsof -t {} \; -exec rm -f {} \; > /dev/null

Con alcune findimplementazioni (incluso FreeBSD da finddove proviene e GNU find), puoi usare -deleteinvece di -exec rm....

Il motivo che stai ricevendo un errore è che non c'è alcun comando tra thene elseed alcune conchiglie (che iniziano con la shell Bourne in cui la sintassi che viene) richiedono almeno uno (e un commento non è un comando). Si noti che è completamente arbitrario e non vi è alcun motivo per cui tali shell lo farebbero. yashe zshnon hanno questa limitazione ( if false; then else echo x; fie persino if false; then else filavorare bene con loro).

Come altri hanno già detto, è possibile utilizzare un comando noop come :(o for nothing in; do nothing; done) o invertire la logica con la !parola chiave (disponibile nelle shell POSIX, ma non nella shell Bourne (scoprirai che l'utilizzo :per quello era comune in quella shell)). mkshe yashcapita di supportare if false; then () else echo x; fi(non mi affiderei ad esso in quanto ciò potrebbe cambiare nelle versioni future).

Un altro approccio è con:

lsof... || {
  cmd1
  cmd2
}

sebbene una differenza sia lo stato generale di uscita che sarà quello di lsofse lsoffallisce.


17
Mentre questo è un modo molto migliore per fare ciò che l'utente di @Novice sta tentando, non risponde affatto alla domanda.
VediJayBee,

Mentre -execè spesso utile, così com'è xargs, a volte è necessario un loop di shell. Nel qual caso un while read nameloop è l'opzione preferita (in bash con GNU find puoi usare l'opzione -0 per entrambi; portabilmente devi rinunciare a newline).
Jan Hudec,

@JanHudec, ci sono modi portabili. -print0è -exec printf '%s\0' {} +(ma portabilmente non puoi gestire quell'output se non vuoi prendere in considerazione perl), e con un find .//.po 'di post-elaborazione, puoi sfuggire alle newline per xargs. Nota che non è un while read, è while IFS= read -r.
Stéphane Chazelas,

@ Chris, ho aggiunto una risposta alla domanda effettiva da quando la risposta è stata accettata.
Stéphane Chazelas

91

Sembra che tu voglia fare una no-op se il file è aperto, quindi dovresti aggiungere un :, che è un comando null in bash:

if lsof "$filename" > /dev/null; then
  # file is open
  :
else
  printf 'deleting %s\n' "$filename"
  rm -- "$filename"
fi

Se non lo usi :, bashnon puoi analizzare il tuo codice e mostrerà un errore simile bash: syntax error near unexpected token 'else'.


mai nuovo di :ed è il primo comando elencato in bash-builtins.
Bolov,

26

Un'altra alternativa: invertire la tua logica.

if ! lsof "$filename" >/dev/null;then
    echo "deleting $filename"
    rm "$filename"
fi

17

TL; DR

Nessuna delle altre risposte in realtà risolve la tua domanda originale sul perché il comando dia un errore di sintassi. Ciò è causato da un comando mancante tra allora e altro .

Un comando mancante

Il tuo codice originale è simile al seguente:

if lsof "$filename" > /dev/null
then
  # file is open
else
  echo "deleting $filename"
  rm "$filename"
fi

Il problema è che hai un commento tra allora e l' altro , ma il commento non viene trattato come un comando. In breve, potresti riscrivere il problema che hai (strutturalmente parlando) come segue:

$ if true; then else echo; fi
bash: syntax error near unexpected token `else'

Correggi la tua sintassi con un Bourne Builtin

È possibile risolvere questo problema inserendo i comandi effettivi prima di altro , ma un commento di per sé non lo farà. La sezione if-then non può essere vuota; se si desidera un segnaposto, è possibile utilizzare l' integrato dei due punti . Per esempio:

$ if true; then :; else echo; fi

Il semplice posizionamento :nella sezione tra allora e l' altro risolverà l'errore di sintassi riscontrato.


1
La risposta di Gnouc, che è anche la più votata, sta già affrontando la domanda originale.
jlliagre,

Rispondi solo per risolvere l'errore di sintassi. FWIW, puoi riprodurre un errore simile con un solo punto e virgola all'inizio di una riga. Questo darà un forte suggerimento. $ ; -bash: syntax error near unexpected token ';'
Matthew Hannigan,
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.