簡単なスクリプトがあります。
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
秒を設定することで、この問題をローカルで確認できます。
タイマースクリプトにSIGINT
シグナルを親プロセスに送信させます($PPID
)。
#!/bin/bash
echo "Going to interrupt $PPID in 5 seconds"
sleep 5
echo "More output"
kill -SIGINT $PPID
sleep 5
このスクリプトがバックグラウンドで実行される場合(./script &
)出力を送信し、スリープしてから、さらに出力を送信してから、プロンプトを強制的に再描画する必要があります。
スクリプトは再びスリープしてから終了します。
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
次のシェルスクリプト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 --notification
コマンドのコメントを解除し、zenity --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