Erro de sintaxe de bash quando “else” segue uma cláusula “then” vazia

31

Por que o script a seguir não é executado, mas gera um erro de sintaxe 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
    
por Novice User 01.06.2014 / 21:05

4 respostas

22

Não use a substituição de comando na saída de find . Aqui tudo pode ser feito com find :

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

Com algumas implementações find (incluindo FreeBSD find de onde vem e GNU find ), você pode usar -delete em vez de -exec rm... .

O motivo pelo qual você está recebendo um erro é que não há comando entre then e else e alguns shells (começando com o shell Bourne de onde vem essa sintaxe) requerem pelo menos um (e um comentário não é um comando). Note que é completamente arbitrário e não há razão para que essas camadas façam isso. yash e zsh não têm essa limitação ( if false; then else echo x; fi e mesmo if false; then else fi funcionam bem com eles).

Como outros já disseram, você pode usar um comando noop como : (ou for nothing in; do nothing; done ) ou inverter a lógica com a palavra-chave ! (disponível em shells POSIX, mas não no shell Bourne (você encontrará que usando : para isso era comum naquele shell)). mksh e yash suportam if false; then () else echo x; fi (eu não confiaria nele, já que isso poderia mudar em versões futuras).

Outra abordagem é com:

lsof... || {
  cmd1
  cmd2
}

embora uma diferença seja o status geral de saída, que será o de lsof se lsof falhar.

    
por 01.06.2014 / 22:13
83

Parece que você quer fazer um no-op se o arquivo estiver aberto, então você deve adicionar um : , que é um comando nulo em bash :

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

Se você não usa : , bash não pode analisar seu código e mostrará erro como bash: syntax error near unexpected token 'else' .

    
por 01.06.2014 / 21:17
25

Outra alternativa: inverta sua lógica.

if ! lsof "$filename" >/dev/null;then
    echo "deleting $filename"
    rm "$filename"
fi
    
por 01.06.2014 / 21:18
14

TL; DR

Nenhuma das outras respostas realmente resolve sua questão original de por que o comando dá um erro de sintaxe. Isso é causado por um comando ausente entre então e else .

Um comando ausente

Seu código original é assim:

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

O problema é que você tem um comentário entre então e else , mas o comentário não é tratado como um comando. Em suma, você poderia reescrever o problema que você tem (estruturalmente falando) da seguinte forma:

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

Corrija sua sintaxe com um Bourne Builtin

Você pode corrigir esse problema colocando comandos reais antes de else , mas um comentário por si só não serve. A seção se-então não pode estar vazia; Se você quiser um marcador, poderá usar o cólon incorporado . Por exemplo:

$ if true; then :; else echo; fi

Basta colocar : na seção entre e e else para corrigir o erro de sintaxe que você está enfrentando.

    
por 02.06.2014 / 03:01