Error de sintaxis Bash cuando "else" sigue una cláusula vacía "then"

36

¿Por qué el siguiente script no se ejecuta, pero da un error de sintaxis de 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
Usuario novato
fuente

Respuestas:

23

No use la sustitución de comandos en la salida defind . Aquí, todo se puede hacer con find:

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

Con algunas findimplementaciones (incluyendo FreeBSD de finddonde proviene y GNU find), puede usar en -deletelugar de -exec rm....

La razón por la que obtiene un error es que no hay un comando entre theny elsealgunos shells (comenzando con el shell Bourne de donde proviene esa sintaxis) requieren al menos uno (y un comentario no es un comando). Tenga en cuenta que es completamente arbitrario y no hay ninguna razón por la cual esos shells harían eso. yashy zshno tienen esa limitación ( if false; then else echo x; fie incluso if false; then else fifuncionan bien con ellos).

Como otros han dicho, puede usar un comando noop como :(o for nothing in; do nothing; done) o revertir la lógica con la !palabra clave (disponible en shells POSIX, pero no en el shell Bourne (encontrará que usar :eso era común en ese shell)). mkshy yashsoporte if false; then () else echo x; fi(no confiaría en ello, ya que eso podría cambiar en futuras versiones).

Otro enfoque es con:

lsof... || {
  cmd1
  cmd2
}

aunque una diferencia es el estado general de salida, que será el de lsofsi lsoffalla.

Stéphane Chazelas
fuente
17
Si bien esta es una manera mucho mejor de hacer lo que está intentando @Novice User, no responde a la pregunta en absoluto.
SeeJayBee
Si bien a -execmenudo es útil, como es xargs, a veces se necesita un bucle de shell. En cuyo caso, un while read namebucle es la opción preferida (en bash con GNU find, puede usar la opción -0 para ambos; de manera portátil, debe renunciar a la nueva línea).
Jan Hudec
@ JanHudec, hay formas portátiles. -print0es -exec printf '%s\0' {} +(pero de forma portátil no puede manejar esa salida, excepto si desea considerarla perl), y con un find .//.poco de procesamiento posterior, puede escapar de las nuevas líneas xargs. Tenga en cuenta que no es un while read, es while IFS= read -r.
Stéphane Chazelas
@ Chris, agregué una respuesta a la pregunta real ya que la respuesta terminó siendo aceptada.
Stéphane Chazelas
91

Parece que desea hacer un no-op si el archivo está abierto, por lo que debe agregar un :comando nulo en bash:

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

Si no lo usa :, bashno puede analizar su código y mostrará un error como bash: syntax error near unexpected token 'else'.

Cuonglm
fuente
nunca es nuevo :y es el primer comando listado en bash-builtins.
bolov
26

Otra alternativa: revierte tu lógica.

if ! lsof "$filename" >/dev/null;then
    echo "deleting $filename"
    rm "$filename"
fi
Joseph R.
fuente
17

TL; DR

Ninguna de las otras respuestas realmente aborda su pregunta original de por qué el comando da un error de sintaxis. Esto es causado por un comando faltante entre entonces y más .

Un comando perdido

Su código original se ve así:

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

El problema es que tiene un comentario entre entonces y más , pero el comentario no se trata como un comando. En resumen, podría volver a escribir el problema que tiene (estructuralmente hablando) de la siguiente manera:

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

Arregle su sintaxis con un Bourne Builtin

Puede solucionar este problema colocando comandos reales antes que otra cosa , pero un comentario por sí solo no servirá. La sección if-then no puede estar vacía; si quieres un marcador de posición, puedes usar el colon incorporado . Por ejemplo:

$ if true; then :; else echo; fi

Simplemente colocando :en la sección entre entonces y de lo contrario se solucionará el error de sintaxis que está experimentando.

CodeGnome
fuente
1
La respuesta de Gnouc, que también es la más votada, ya está abordando la pregunta original.
jlliagre
Solo responda para abordar el error de sintaxis. FWIW, puede reproducir un error similar con un punto y coma al comienzo de una línea. Esto le dará una pista fuerte. $ ; -bash: syntax error near unexpected token ';'
Matthew Hannigan