bash: saída diferente entre CTRL-C e “limpeza ordenada”

3

Eu realmente tentei encontrar um título melhor para essa pergunta. Estou aberto a sugestões.

Eu escrevi um script bash que captura EXIT e chama uma função se esse sinal for recebido. Chama a mesma função quando existe um arquivo chamado stop . Aqui está:

#!/bin/bash

TAIL_PID=0
CAT_PID=0

DEVICE=/dev/ttyACM0
WDIR=plasma
LOGFILE=$WDIR/$(date +%Y%m%d_%H%M%S.log)
CMDFILE=$WDIR/toDevice

function kill_tail
{
  if [ $TAIL_PID -ne 0 ]
  then
    kill $TAIL_PID
    TAIL_PID=0
    echo "killed tail"
  fi
}

function kill_cat
{
  if [ $CAT_PID -ne 0 ]
  then
    kill $CAT_PID
    CAT_PID=0
    echo "killed cat"
  fi
}

function on_die
{
  echo 't 0' >> $DEVICE
  kill_tail
  kill_cat
  echo "stopped logging"
}
trap on_die EXIT

# mount plasma oven directory if it is not already mounted
mountpoint -q $WDIR || sshfs user@server:plasma $WDIR    
# see if device is available/wait for device
while [ ! -c $DEVICE ]
do
  sleep 1
done
echo "Found controller"

# stop output, remove start and stop files
echo 't 0' >> $DEVICE
rm $WDIR/start $WDIR/stop

# outer loop
while [ 1 ]
do
  while [ ! -f $WDIR/start ]
  do
    sleep 1
  done
  rm $WDIR/start

  # stop output
  echo 't 0' >> $DEVICE

  # pass commands to device
  # but clear existing commands first
  > $CMDFILE
  tail -f $CMDFILE > $DEVICE &
  TAIL_PID=$!
  echo "tail PID = " $TAIL_PID

  # start logging
  cat $DEVICE >> $LOGFILE &
  CAT_PID=$!
  echo "cat PID = " $CAT_PID

  # start output
  echo 't 1000' >> $DEVICE
  echo "started logging to " $LOGFILE

  while [ ! -f $WDIR/stop ]
  do
    sleep 1
  done
  rm $WDIR/stop

  on_die

done # end of outer loop

Quando executo esse script, depois de touch start , ele me dá uma saída diferente, dependendo se eu CTRL-C ou touch stop . Esta é a saída após CTRL-C ing:

killed tail
killed cat
stopped logging

Esta é a saída após touch stop :

killed tail
killed cat
stopped logging
./mountPlasma: line 93: 21200 Terminated              tail -f $CMDFILE > $DEVICE
./mountPlasma: line 93: 21201 Terminated              cat $DEVICE >> $LOGFILE

Por quê? A mesma função é chamada, e eu esperaria a mesma saída de ambas as chamadas para on_die . A saída indica que as duas mensagens extras são emitidas na linha 93, que é done # end of outer loop (o número da linha não corresponde exatamente ao código acima, pois eu tive que remover algumas linhas para este post).

Como sou muito inexperiente com o bash, não sei se há algum efeito colateral nisso. Tanto tail como cat são eliminados como esperado.

    
por Christoph 16.04.2013 / 00:14

1 resposta

1

Quando você atinge Ctrl-C , o script em execução obtém SIGINT e o propaga para seus filhos, enquanto na saída "regular" ele envia o SIGTERM padrão (da função registrada com EXIT ).

Dito isso, há uma grande diferença entre Ctrl-C e a condição de parada. Enquanto a função de manipulador de saída é chamada em ambos os casos, os eventos reais são completamente diferentes. No caso do SIGINT, os processos filhos são mortos por esse (ou pelo menos provavelmente são) e o shell interpretando o script não tem muita chance de relatar essa mudança de estado. No outro caso, ele pega o SIGCHLD dos programas encerrados e exibe a mensagem informativa.

Agora, você também pode receber a mensagem no SIGINT, desde que você tenha tempo suficiente para verificar o shell de interpretação (mais precisamente - já que não acho que o shell esteja deixando processos zumbis nessa situação - para relatar o status de ) seus processos filhos. Uma maneira de fazer isso seria usar o wait builtin para esperar ativamente por todos ou por processos especificados para alterar o estado. Explodir o manipulador de saída (por exemplo, com outro sleep ) pode ser uma opção também, mas observe que essa é uma condição de corrida entre o intérprete que encerra e verifica seus filhos (portanto, o bloqueio wait é o caminho seguro fazer isso).

    
por 17.04.2013 / 00:05

Tags