シェルスクリプトを一時停止するには任意のキーを押し、再開するにはもう一度押します


10

ファイルをコピーし、ファイルごとにその進行状況をエコーするAPIをテストするためのシェルスクリプトを作成しました。

各コピーの間には2秒間のスリープがあるため、任意のキーを押してスクリプトを一時停止し、より詳細なテストを行う機能を追加したいと思います。次に、任意のキーを押して再開します。

これをできるだけ少ない行に追加するにはどうすればよいですか?

回答:


12

スクリプトに何かを追加する必要はありません。シェルはそのような機能を可能にします。

  • ターミナルでスクリプトを開始します。
  • が実行中であり、端末の使用をブロックしている間ctrl- z。端末が再び解放され、プロセスが停止したというメッセージが表示されます。(現在、Porcess状態でT、停止しています)
  • 今あなたがしたいことを何でもしてください。他のプロセス/スクリプトを開始してctrl-で停止することもできzます。
  • jobs端末を入力するか、停止したすべてのジョブを一覧表示します。
  • スクリプトを続行するには、「fg(フォアグラウンド)」と入力します。ジョブを再開してフォアグラウンドプロセスグループに戻し、ジョブの実行を継続します。

例を見る:

root@host:~$ sleep 10 # sleep for 10 seconds
^Z
[1]+  Stopped                 sleep 10
root@host:~$ jobs # list all stopped jobs
[1]+  Stopped                 sleep 10
root@host:~$ fg # continue the job
sleep 10
root@host:~$ # job has finished

あなたが言ったように、私が実行sleep 10; notify-send helloしてCTRL + Zを押して停止すると、notify-send hello実行されます。2番目のコマンドが実行されている場合、どうして最初のプロセスが停止するのですか?タイプがあればその後のfg2番目のコマンドは、既に実行されているので、私は、明白である、何が起こって見るカント
エドワード・トーバルズ

@edwardtorvaldsは、2つのコマンドが別々であるためです。スクリプトでは、それらはサブシェルになります。それらを簡単なスクリプトで記述し、スクリプトを実行します。次にctrl-zを押して停止すると、最初のコマンドが完了するまで2番目のコマンドが実行されないことがわかります。書くことcmd; cmd; cmd;は書くことのようなものcmd <newline> cmd <newline> ...です。あなたが書くことができるスクリプトの代わりに( cmd; cmd; cmd; )、それはスクリプトのように振る舞います、それによって生成されたサブシェルのせいで(
chaos

私も試しましたsleep 10。3秒後にCTRL + Zを押して数秒後に再開すると、スリープコマンドが7秒未満で終了することに気付きました。これは、あなたが言ったこととは逆です。コマンドは決して停止されないため、バックグラウンドで実行されるだけです。
エドワードトーバルズ2014年

@edwardtorvalds私も気づいた...意味がわからない。私はstracedのsleepコマンドを使用してシステムコールがあることが分かりましたnanosleep()。これは、nanosleepシステムコールの明確な動作のようです。restart_syscall()既に経過した時間(プロセスがシグナルによって停止された時間を含む)を考慮して適切に調整された時間引数を使用して、中断されたシステムコールを再開します。そのマンページをお読みください:man7.org/linux/man-pages/man2/restart_syscall.2.html
chaos

@chaosの回答を完了するためのいくつかの注意事項(自由に含めてください):ctrl-Zを押すと、ジョブは一時停止(「停止」)するため、現時点では実行されておらず、続行するかどうかの決定を待っていますフォアグラウンド(例:)fg %1またはバックグラウンド(例:)bg %1。(ジョブが示す数が1つだけ、つまり一時停止されたプロセスが1つだけの[1]+ stopped sleep 10場合、カオスが示す例:のみ、%nパーツを省略できます。バックグラウンドプロセスが複数ある場合(実行中または停止中)、必要なプロセスを指定する必要がありますwith:(%n例: fg %2 %2をフォアグラウンドで再開させるため))
Olivier Dulac

6

スクリプト内に留まったままスクリプトを一時停止したい場合は、スリープの代わりに読み取りを使用できます。

使用できます

read -t
read -nスクリプトを続行するために、1文字を読み取るための読み取りのタイムアウトを設定する(事実上任意のキーを押す)

コードを提供していないため、以下はコードの使用例です。
qを押すとread -n1、キーが押されるまでスクリプトが続行されなくなります。
キーが押されると、チェックがリセットされ、スクリプトは通常どおりループを続行します。

while [[ true ]]; do
    read -t2 -n1 check
    if [[ $check == "q" ]];then
        echo "pressed"
        read -n1
        check=""
    else
        echo "not pressed"
    fi
echo "Doing Something"
done

またstty -echo、セクションの先頭とstty echo末尾に追加して、入力によって画面出力が混乱しないようにすることもできます。


@mikeserv私はopが何を読んでも気にしないと思います、彼らはただスクリプトを一時停止して再開したいだけです、ターミナル設定も保存することはどういう意味ですか、私は1つだけ変更しているので少しやり過ぎに見えます。

1
@mikeservああそうだ、私はすべてのstdinがユーザーから来ると思っていた。

1

を使用ddすると、ファイルから1バイトを確実に読み取ることができます。を使用sttyするminと、端末の読み取りとtime出力を10分の1秒で修飾するバイト数を設定できます。これら2つを組み合わせるsleepと、完全になくても行うことができると思います。ターミナルの読み取りタイムアウトが機能するだけです。

s=$(stty -g </dev/tty)
(while stty raw -echo isig time 20 min 0;test -z "$(
dd bs=1 count=1 2>/dev/null; stty "$s")" || (exec sh)
do echo "$SECONDS:" do your stuff here maybe                             
   echo  no sleep necessary, I think                                                          
   [ "$((i+=1))" -gt 10 ] && exit                                                             
done       
) </dev/tty

これは、while私が試してみるために模造した小さなループの例です。2秒ごとddに、読み取られたstdin-リダイレクトされた/dev/tty-およびwhileループループでタイムアウトします。これdd 、キーを押したためにタイムアウトしないか、または対話型のシェルが呼び出されるためタイムアウトしません

これがテスト実行です-各行の先頭に出力される数字はシェル変数の値です$SECONDS

273315: do your stuff here maybe
no sleep necessary, I think
273317: do your stuff here maybe
no sleep necessary, I think
273319: do your stuff here maybe
no sleep necessary, I think
273321: do your stuff here maybe
no sleep necessary, I think
sh-4.3$ : if you press a key you get an interactive shell
sh-4.3$ : this example loop quits after ten iterations
sh-4.3$ : or if this shell exits with a non-zero exit status
sh-4.3$ : and speaking of which, to do so you just...
sh-4.3$ exit
exit
273385: do your stuff here maybe
no sleep necessary, I think
273387: do your stuff here maybe
no sleep necessary, I think
273389: do your stuff here maybe
no sleep necessary, I think
273391: do your stuff here maybe
no sleep necessary, I think
273393: do your stuff here maybe
no sleep necessary, I think
273395: do your stuff here maybe
no sleep necessary, I think
273397: do your stuff here maybe
no sleep necessary, I think

stty sanesttyの設定を変更した後は使用しないでください。間違っている可能性がありますが、どこかでリセットしたようには見えませんか?

@Jidder-いいえスクリプトの上部にあるターミナルの状態をで保存しs=$(stty -g </dev/tty)ます。電話ddをかけた直後に、で復元しstty "$s"ます。最終状態はサブシェルを考慮しないため、これらの設定は親シェルに関係なく保持されます。stty sane必ずしもあなたがしたいことではありません- saneその時点での状態であると想定するよりも、状態をあなたが見つけた方法に復元する方が良いです。私がそれを復元していなかったとしたら、それらはあちこちにありechoます。私がテストを始めたとき、あなたの答えはここにありませんでした。
mikeserv 2014年
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.