如何在执行睡眠命令后退出命令提示符?

如何在执行睡眠命令后退出命令提示符?

我有一个简单的脚本:

f=1 # initial value
loop(){
...    
    if [[ $f -eq 1 ]]
    then
        echo $msg1
        f=2
        (sleep $interval; loop) &
        exit 1
    elif [[ $f -eq 2 ]]
    then
        echo $msg2
        f=1
        (sleep $interval; loop) &
        exit 2
    fi
...
}

它的目的是在这两个消息之间一个接一个地循环。我这样做,而不是正常的 while 循环,因为我希望脚本处于后台。所以,我期望在我的终端中发生的是:

gt@gt:~./timer.sh
<msg1>
gt@gt:~<me running some other commands>
<some output>
gt@gt:~<as soon as $interval time gets over>
<msg2>
gt@gt:~<fresh prompt>

正如您所看到的,我希望 msg2 出现在正常回显输出出现的位置,并且紧接着它应该留下一个新的命令输入提示。但实际发生的情况是:

gt@gt:~./timer.sh
<msg1>
gt@gt:~<me running some other commands>
<some output>
gt@gt:~<msg2>
<same prompt is still waiting for input here>

如何解决这个问题?

您可以通过运行#!/bin/bash并设置sleep=3秒数在本地验证此问题。

答案1

让您的计时器脚本将SIGINT信号发送到父进程 ( $PPID)。

例子

#!/bin/bash
echo "Going to interrupt $PPID in 5 seconds"
sleep 5
echo "More output"
kill -SIGINT $PPID
sleep 5

当此脚本在后台 ( ./script &) 运行时,它应该发送输出、睡眠,然后发送更多输出,然后强制重新绘制提示。

该脚本将再次休眠,然后退出。

更新OP的脚本

f=1 # initial value
loop(){
...    
    if [[ $f -eq 1 ]]
    then
        echo $msg1
        kill -SIGINT $PPID
        f=2
        (sleep $interval; loop) &
        exit 1
    elif [[ $f -eq 2 ]]
    then
        echo $msg2
        kill -SIGINT $PPID
        f=1
        (sleep $interval; loop) &
        exit 2
    fi
...
}

当您的 shell 进程被信号中断时,您将丢失待处理的输入行,但命令提示符将在计时器脚本输出后重新绘制。

编辑

要在子脚本中重现此行为,请将父 PID 环境变量从调用者脚本传递到子脚本中。

main.sh

...
./timer.sh $PPID
...
#exits

timer.sh

...
# Save the parent pid argument
gp=$1
...
# Replace instances of $PPID with $gp in timer.sh
...
kill -SIGINT $gp

答案2

我认为下面的shell脚本timer会做你想做的事或者做一些接近你想做的事。

#!/bin/bash

interval=60  # seconds
tips="Skip waiting with Yes|Enter, exit with No|Escape"
msg1="First message ...

$tips"
msg2="Second message ...

$tips"

f=1 # initial value
while true
do
    if [[ $f -eq 1 ]]
    then
#        zenity --notification --text="$msg1" 2> /dev/null
        LANG=C zenity --question --title="${0##*/}" \
        --text="$msg1" --timeout="$interval" --width=400 2> /dev/null
    elif [[ $f -eq -1 ]]
    then
#        zenity --notification --text="$msg2" 2> /dev/null
        LANG=C zenity --question --title="${0##*/}" \
        --text="$msg2" --timeout="$interval" --width=400 2> /dev/null
    fi
    ans=$?
    if [ $ans -eq 0 ] || [ $ans -eq 5 ]
    then
     f=$((-f))
    else
      zenity --info --title="${0##*/}" \
        --text="Exiting now" --timeout="3" 2> /dev/null
     break
    fi
done & pid=$!

echo "kill with
kill $pid       # useful during testing 
--------------------------------------------"
  • 我用zenity --question发送消息,这应该没问题,如果它们很少出现,并且您确实想注意到它们(并且可能做某事)。这样你也可以优雅地退出后台任务。

    在此输入图像描述

  • 取消注释zenity --notificationzenity --question命令,如果您想要较少侵入性的消息,请将命令注释掉。

    您还应该在各行sleep $interval之后输入命令行zenity --notification

    但这也意味着您必须使用其进程号来终止后台进程,

    kill <process number>
    

    当您启动计时器shell脚本时,会显示实际的进程号,您可以通过以下方式找到它ps

    $ ./timer
    kill with
    kill 15585       # useful during testing 
    --------------------------------------------
    $ ps -e |grep timer
    15585 pts/3    00:00:00 timer
    

相关内容