1. 序章

Linuxユーザーとして、私たちはしばしばターミナルを使用してさまざまなコマンドやプログラムを実行します。 さまざまなシナリオで完了するのに1分以上かかるコマンドを実行します。 このような場合、ターミナルを他の作業に使用できるように、コマンドをバックグラウンドで実行することをお勧めします。 または、 SSH セッションでコマンドをリモートで実行している場合もあります。その場合、バックグラウンドでプロセスを開始し、その後セッションを終了できます。

このチュートリアルでは、ターミナルからプロセスを完全に切り離すいくつかの方法を見ていきます。いくつかのメソッドを使用してバックグラウンドでプロセスを開始できますが、いくつかのメソッドはすでに実行中のプロセスをに移動するのに役立ちます背景。

2. bg fg 、およびジョブを使用する

コマンドの実行が開始されたら、 Ctrl + Zを押してプロセスをフリーズし、bgコマンドを使用してバックグラウンドで再開できます。次に、jobsコマンドを使用して実行中のバックグラウンドプロセスを表示します。

$ sleep 10
^Z
[1]+  Stopped                 sleep 10
$ bg
[1]+ sleep 10 &
$ jobs
[1]+  Running                 sleep 10 &
$ echo

[1]+  Done                    sleep 10

上記のスニペットは、 Ctrl + Z で停止し、bgでバックグラウンドに移動したプロセスの出力を示しています。 jobs コマンドを実行すると、前のコマンドは確かにまだ実行されていますが、バックグラウンドで実行されています。 10秒後に別のランダムコマンド( echo )を実行すると、最初のコマンドが完了したことがわかります。

bg コマンドを使用してプロセスをバックグラウンドに移動すると、fgコマンドを使用してプロセスをフォアグラウンドに戻すことができます。

$ (sleep 11 && echo hello)
^Z
[1]+  Stopped                 ( sleep 11 && echo hello )
$ bg
[1]+ ( sleep 11 && echo hello ) &
$ fg
( sleep 11 && echo hello )
hello

上記のスニペットでは、最初のコマンドは11秒間待機し、「hello」を出力することになっています。 それをバックグラウンドに送信し、 fg、を使用してフォアグラウンドに戻すと、コマンドがフォアグラウンドに「hello」を出力することがわかります。

3. &演算子の使用

私たちはできる末尾に「&」を追加して、バックグラウンドでコマンドを開始しますコマンドの:

$ gedit &
[1] 968967
$ 
(gedit:968967): GtkSourceView-WARNING **: 16:15:38.174: could not parse color '#bg'

(gedit:968967): GtkSourceView-WARNING **: 16:15:38.175: no color named 'white'
$ echo "running another command"
running another command
$ kill 968967

上記から、 gedit コマンドにアンパサンドを追加すると、バックグラウンドに送信され、そのPID968967が出力されることがわかります。 GeditはGUIプログラムであり、ターミナルを自由に使用して他のコマンドを実行しながら、デスクトップ上で開きます。 PIDに対してkillコマンドを実行すると、プログラムは終了します。

また、geditコマンドからの出力がまだこの端末に出力されていることもわかります。 これを回避するために、出力を別の場所、たとえば / dev /nullにリダイレクトできます。

$ gedit 1>/dev/null 2>/dev/null &
[1] 979813
$ kill 979813
$ echo "hello"
hello
[1]+  Terminated              gedit > /dev/null 2> /dev/null

この場合、出力ストリームとエラーストリームを / dev / null、にリダイレクトし、以前に表示された出力が抑制されるようになりました。 その結果、最初に端末でPIDの通知を受け取るのは、プロセスが終了したときだけです。

4. nohupを使用する

nohupコマンドは、「ハングアップ」や端末の切断の影響を受けない方法でコマンドを実行するために使用されます。 nohupを使用してコマンドを開始すると、コマンドは出力を nohup.out

$ nohup echo hello &
[1] 998797
nohup: ignoring input and appending output to 'nohup.out'
$
^C
[1]+  Done                    nohup echo hello
$ cat nohup.out
hello

上記のスニペットでは、を使用してコマンドを開始します nohup 、末尾に「&」を追加して、端末が他のコマンドを自由に実行できるようにします。 プロセスが完了すると、コマンドの出力がnohup.outファイルに表示されます。

5. disownを使用する

コマンドを実行して 「&disown」を追加して、端末にプロセスの所有権を剥奪させます最後に:

$ echo hello & disown
[1] 1007802
hello

勘当した後、コマンドが最初にPIDを出力し、次にプログラムからの出力が出力されることがわかります。これはまだ端末に表示されます。 出力を無音にするために、前に行ったように、 / dev / null、にリダイレクトできます。

$ echo hello 1>/dev/null 2>/dev/null & disown
[1] 1016729

これで、コマンドはPIDのみを出力し、コマンドの出力は出力しません。

6. setsidを使用する

いつ setsidを使用してコマンドを実行すると、コマンドは現在の端末から切断された新しいセッションで開始されます。 勘当して「 「、出力は現在の端末に出力され、に送信することで無音にすることができます / dev / null

$ setsid echo hello
hello
$ setsid echo hello 1>/dev/null 2>/dev/null

後者の場合、コマンドは端末に出力を出力しません。

7. 画面を使用する

Screen は、複数の仮想端末を起動および管理できるウィンドウマネージャーです。 画面を使用してバックグラウンドでプロセスを実行するには、新しいウィンドウを作成し、そこでプロセスを開始して、ウィンドウを切り離します。

7.1. スクリーンウィンドウに入る

新しい画面ウィンドウに入るには、screenコマンドを入力するだけです。

$ screen
[screen_window] $ 

入ったら、 Ctrl + A に続いて”(二重引用符)を押して、アクティブなすべての画面ウィンドウを一覧表示できます。

[screen_window] 
Ctrl+A " 
 Num Name 
   0 bash

画面ウィンドウが1つしかないことがわかります。 「[screen_window]」は、元の端末と区別するためにのみコードスニペットに表示されており、実際には出力に出力されないことに注意してください。

7.2. 画面ウィンドウでコマンドを開始します

次に、画面ウィンドウ内で長時間実行されるコマンドを開始しましょう。

$ watch -n 1 date

これにより、 Ctrl + C:を使用して終了するまで、毎秒継続的に更新される以下のような出力が表示されます。

Every 1.0s: date                          dell: Thu Jun  2 17:13:14 2022

Thursday 02 June 2022 05:13:14 PM IST

7.3. 画面ウィンドウから切り離す

これで、この画面ウィンドウから切り離して、 Ctrl + A を押してからd:を押すことにより、元のターミナルセッションに戻ることができます。

[screen_window}
Ctrl+A d
$ screen
[detached from 1045567.pts-1.dell] 

元の端末に戻ると、前に入力した画面コマンドが表示されます。 また、以下にいくつかの新しい出力が表示されます。これは、画面ウィンドウから切り離してここに戻ったことを示しています。

7.4. 画面ウィンドウに戻る

-Rフラグを指定してscreenを実行すると、画面ウィンドウに再び入ることができます。

$ screen -R
[screen_window]
Every 1.0s: date                     dell: Thu Jun  2 17:23:05 2022

Thursday 02 June 2022 05:23:05 PM IST

以前に開始したwatchコマンドがこの画面ウィンドウ内でまだ実行されていることがわかります。

7.5. 画面ウィンドウを終了します

この画面ウィンドウを終了するには、 Ctrl +Cを押してプロセスを停止します。 次に、exitコマンドを使用してウィンドウを閉じます。

[screen_window]
Ctrl+C
[screen_window] $ exit

$ screen -R
[screen is terminating]

画面ウィンドウを終了した後、元の端末に戻ります。 ここでは、以前に実行した screen -R コマンドと、screenが終了していることを示す出力が表示されます。

8. pm2を使用する

端末からプログラムを切り離して永久に実行し続ける必要がある場合は、pm2というプログラムを使用できます。これは、24時間365日オンラインである必要があるアプリケーションサーバーまたはボットの実行に最適です。クラッシュが発生した場合は自動的に再起動します。 Pm2がすべてを処理します。

8.1. pm2をインストールしています

pm2、をインストールする前に、次のコマンドを実行して、nodejsnpmがインストールされていることを確認する必要があります。

$ node -v
v14.18.1
$ npm -v
6.14.15

次に、pm2をインストールできます。

$ sudo npm install -g pm2

8.2. pm2でプログラムを実行する

pm2 start:を使用して、pm2nodejsプログラムを開始できます。

$ pm2 start test.js
[PM2] Spawning PM2 daemon with pm2_home=/home/kd/.pm2
[PM2] PM2 Successfully daemonized
[PM2] Starting /home/kd/tinkering/test.js in fork_mode (1 instance)
[PM2] Done.
┌────┬────────────────────┬──────────┬──────┬───────────┬──────────┬──────────┐
│ id │ name               │ mode     │ ↺    │ status    │ cpu      │ memory   │
├────┼────────────────────┼──────────┼──────┼───────────┼──────────┼──────────┤
│ 0  │ test               │ fork     │ 0    │ online    │ 0%       │ 27.5mb   │
└────┴────────────────────┴──────────┴──────┴───────────┴──────────┴──────────┘
[PM2][WARN] Current process list is not synchronized with saved list. App start_bot differs. Type 'pm2 save' to synchronize.

プログラムが開始したら、 pm2 status:を実行して現在のステータスを表示できます。

$ pm2 status
┌────┬────────────────────┬──────────┬──────┬───────────┬──────────┬──────────┐
│ id │ name               │ mode     │ ↺    │ status    │ cpu      │ memory   │
├────┼────────────────────┼──────────┼──────┼───────────┼──────────┼──────────┤
│ 0  │ test               │ fork     │ 18   │ online    │ 0%       │ 40.8mb   │
└────┴────────────────────┴──────────┴──────┴───────────┴──────────┴──────────┘
[PM2][WARN] Current process list is not synchronized with saved list. App start_bot differs. Type 'pm2 save' to synchronize.

pm2は主にnodejsプログラムを実行するために構築されましたが、Pythonプログラムなどの他のプログラムを処理できます。

$ pm2 start test.py
[PM2] Starting /home/kd/tinkering/test.py in fork_mode (1 instance)
[PM2] Done.
┌────┬────────────────────┬──────────┬──────┬───────────┬──────────┬──────────┐
│ id │ name               │ mode     │ ↺    │ status    │ cpu      │ memory   │
├────┼────────────────────┼──────────┼──────┼───────────┼──────────┼──────────┤
│ 0  │ test               │ fork     │ 37   │ online    │ 100%     │ 37.3mb   │
│ 1  │ test               │ fork     │ 0    │ online    │ 0%       │ 4.0kb    │
└────┴────────────────────┴──────────┴──────┴───────────┴──────────┴──────────┘
[PM2][WARN] Current process list is not synchronized with saved list. App start_bot differs. Type 'pm2 save' to synchronize.

pm2が開始されたすべてのプログラムにIDを割り当てることがわかります。 このIDを使用して、出力を表示したり、プログラムを停止したりできます。

$ pm2 logs 0
[TAILING] Tailing last 15 lines for [0] process (change the value with --lines option)
/home/kd/.pm2/logs/test-error.log last 15 lines:
/home/kd/.pm2/logs/test-out.log last 15 lines:
0|test     | hello
0|test     | hello
0|test     | hello
0|test     | hello
0|test     | hello
0|test     | hello
0|test     | hello
0|test     | hello
0|test     | hello
0|test     | hello
0|test     | hello
0|test     | hello
0|test     | hello
0|test     | hello
0|test     | hello
$  pm2 stop 0
[PM2] Applying action stopProcessId on app [0](ids: [ '0' ])
[PM2] [test](0) ✓
┌────┬────────────────────┬──────────┬──────┬───────────┬──────────┬──────────┐
│ id │ name               │ mode     │ ↺    │ status    │ cpu      │ memory   │
├────┼────────────────────┼──────────┼──────┼───────────┼──────────┼──────────┤
│ 0  │ test               │ fork     │ 94   │ stopped   │ 0%       │ 0b       │
│ 1  │ test               │ fork     │ 15   │ errored   │ 0%       │ 0b       │
└────┴────────────────────┴──────────┴──────┴───────────┴──────────┴──────────┘
[PM2][WARN] Current process list is not synchronized with saved list. App start_bot differs. Type 'pm2 save' to synchronize.

「hello」を出力して終了するように両方のプログラムを作成し、pm2は終了するたびに再起動を試みます。 そのため、出力に「こんにちは」という一連の行が表示されます。

9. 結論

このチュートリアルでは、ターミナルから切り離されたプログラムを実行するいくつかの方法を確認しました。

私たちはできる &演算子、およびnohup、disown、setsid、およびscreenコマンドを使用して、端末から切り離されたプロセスを開始します。 でも、 すでに開始されているプロセスをデタッチするには、bgコマンドを使用する必要がありますを使用してプロセスを一時停止した後 Ctrl + Z

また、アプリケーションサーバーの実行などのより複雑なシナリオに使用できるpm2コマンドについても説明しました。 ただし、これはデフォルトで一般的なLinuxディストリビューションにバンドルされていません。 他の依存関係と一緒にインストールする必要があります。