sleepコマンドを実行した後にコマンドプロンプトを終了するには?

sleepコマンドを実行した後にコマンドプロンプトを終了するには?

簡単なスクリプトがあります。

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
...
}

その目的は、これら2つのメッセージの間を順番に繰り返すことです。私はスクリプトがバックグラウンドにありたいので、通常の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
...
}

シェルプロセスがシグナルによって中断されると、保留中の入力行は失われますが、コマンドプロンプトはタイマースクリプトの出力後に再描画されます。

編集する

サブスクリプトでこの動作を再現するには、呼び出し側スクリプトの親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

私の考えでは、次のシェルスクリプトは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>
    

    タイマーシェルスクリプトを起動すると、実際のプロセス番号が表示されます。ps

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

関連情報