bash:CTRL-C 与“有序清理”之间的不同输出

bash:CTRL-C 与“有序清理”之间的不同输出

我真的很努力为这个问题找到一个更好的标题。我愿意接受建议。

我编写了一个 bash 脚本,EXIT如果收到该信号,它会捕获并调用一个函数。当调用的文件stop存在时,它会调用相同的函数。这里是:

#!/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

当我运行此脚本时, after touch start,它会根据 ICTRL-Ctouch stop.这是 ing 后的输出CTRL-C

killed tail
killed cat
stopped logging

这是之后的输出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

为什么?调用相同的函数,我希望两次调用都有相同的输出on_die。输出表明两条额外的消息是在第 93 行发出的done # end of outer loop(行号与上面的代码不完全匹配,因为我必须为这篇文章删除几行)。

由于我对 bash 非常缺乏经验,我不知道这是否有任何副作用。tail和都cat如预期被杀死了。

答案1

当您点击 时Ctrl-C,正在运行的脚本会获取 SIGINT 并将其传播给它的子级,而在“常规”退出时,它将发送默认的 SIGTERM (来自使用 注册的函数EXIT)。

Ctrl-C也就是说,和停止条件之间有很大的区别。虽然在这两种情况下都会调用退出处理程序函数,但实际事件完全不同。在 SIGINT 的情况下,子进程被该进程杀死(或者至少可能被杀死)解释脚本的 shell 没有太多机会报告此状态更改。在另一种情况下它捕获信号灯从终止的程序中并显示信息消息。

现在,您也可以在 SIGINT 上获取消息,前提是您给解释 shell 足够的时间来检查(更准确地说 - 因为我认为 shell 不会离开僵尸进程在这种情况下——报告状态) 其子进程。一种方法是使用wait内置函数主动等待所有或指定进程更改状态。炸毁退出处理程序(例如,使用另一个sleep)也可能是一种选择,但请注意,这实际上是解释器终止和检查其子级之间的竞争条件(因此阻塞wait是执行此操作的安全方法)。

相关内容