リモートホストにバックグラウンドで処理を実行させる方法
[履歴] [最終更新] (2015/07/12 09:00:13)
プログラミング/IoT の関連商品 (Amazonのアソシエイトとして、当メディアは適格販売により収入を得ています。)
最近の投稿
注目の記事

やりたいこと

hello.sh

#!/bin/sh
while :
do
    date
    sleep 1
done

ローカルホストにおけるバックグラウンド処理はコマンドの後に '&' を付与することで実現できます。リダイレクションについてはこちらをご参照ください。

$ ./hello.sh > out.txt 2>&1 &

$ tailf out.txt
2015年  6月 15日 月曜日 20:07:37 UTC
2015年  6月 15日 月曜日 20:07:38 UTC

$ jobs
[1]+  実行中               ./hello.sh > out.txt &

$ fg
./hello.sh > out.txt
Ctrl-C

リモートホストにおけるフォアグラウンド処理は ssh コマンドの後に所望の処理を記述することで実現できます。

$ ssh REMOTEHOST "./hello.sh"
2015年  6月 15日 月曜日 20:09:58 UTC
2015年  6月 15日 月曜日 20:09:59 UTC

リモートホストにおけるバックグラウンド処理を実現するためにはどうしたらよいでしょうか。

方法1 ('&')

ローカルホストにおけるバックグラウンド処理と同様に '&' を付与することで実現できます。

$ ssh REMOTEHOST "./hello.sh > out.txt 2>&1 &"
$ ssh REMOTEHOST "tailf out.txt"
2015年  6月 15日 月曜日 20:16:20 UTC
2015年  6月 15日 月曜日 20:16:21 UTC

しかしながらプロセスによってはターミナル終了時に送信される可能性のある SIGHUP で処理が停止してしまいます。その場合は次の方法を検討します。

補足

シグナルは UNIX 系 OS においてプロセス間の非同期通信などで使用されます。様々な種類のシグナルがあります。

$ kill -l
 1) SIGHUP       2) SIGINT       3) SIGQUIT      4) SIGILL       5) SIGTRAP
 6) SIGABRT      7) SIGBUS       8) SIGFPE       9) SIGKILL     10) SIGUSR1
11) SIGSEGV     12) SIGUSR2     13) SIGPIPE     14) SIGALRM     15) SIGTERM
16) SIGSTKFLT   17) SIGCHLD     18) SIGCONT     19) SIGSTOP     20) SIGTSTP
21) SIGTTIN     22) SIGTTOU     23) SIGURG      24) SIGXCPU     25) SIGXFSZ
26) SIGVTALRM   27) SIGPROF     28) SIGWINCH    29) SIGIO       30) SIGPWR
31) SIGSYS      34) SIGRTMIN    35) SIGRTMIN+1  36) SIGRTMIN+2  37) SIGRTMIN+3
38) SIGRTMIN+4  39) SIGRTMIN+5  40) SIGRTMIN+6  41) SIGRTMIN+7  42) SIGRTMIN+8
43) SIGRTMIN+9  44) SIGRTMIN+10 45) SIGRTMIN+11 46) SIGRTMIN+12 47) SIGRTMIN+13
48) SIGRTMIN+14 49) SIGRTMIN+15 50) SIGRTMAX-14 51) SIGRTMAX-13 52) SIGRTMAX-12
53) SIGRTMAX-11 54) SIGRTMAX-10 55) SIGRTMAX-9  56) SIGRTMAX-8  57) SIGRTMAX-7
58) SIGRTMAX-6  59) SIGRTMAX-5  60) SIGRTMAX-4  61) SIGRTMAX-3  62) SIGRTMAX-2
63) SIGRTMAX-1  64) SIGRTMAX

kill コマンドの -s オプションによって任意のシグナルをプロセス ID 指定で送信できます。

$ kill -s 15 PID

代表的なものをいくつか抜粋します。

  • SIGHUP (=1, hangup) → ターミナル終了時にログインシェルによって送信
  • SIGINT (=2, interrupt) → Ctrl-C で送信
  • SIGTERM (=15, termination) → kill コマンドで -s オプション無指定時に送信

プロセスによっては SIGHUP を無視して処理を継続します。特に一部のデーモンプロセスは SIGHUP を終了ではなく再起動のために利用します。シグナルのキャッチについてはこちらをご参照ください。

方法2 (nohup)

nohup コマンドを利用することで SIGHUP を無視するプロセスを生成できます。/dev/null で標準入力を閉じています。

$ ssh REMOTEHOST "nohup ./hello.sh > out.txt 2>&1 < /dev/null &"
$ ssh REMOTEHOST "tailf out.txt"
2015年  6月 15日 月曜日 21:14:00 UTC
2015年  6月 15日 月曜日 21:14:01 UTC

kill コマンドで SIGHUP を送信してもプロセスが停止されないことが分かります。

$ pgrep -l hello.sh
10084 hello.sh
$ kill -s 1 10084
$ pgrep -l hello.sh
10084 hello.sh

しかしながら SIGHUP 以外のシグナルは無視できません。何らかの原因によって処理が停止してしまう場合は次の方法を検討します。

方法3 (screen)

screen はこちらで紹介した tmux と同様に仮想端末を提供するコマンドです。手動でログインする場合に screen または tmux を利用してリモート処理をターミナルを閉じても継続して実行できることはよく知られています。あまり知られていないですが、それに加えて、実は screen または tmux コマンドは nohup と同様に ssh の引数内でも利用できます。自動化時に重宝します。ファイルへのリダイレクトは bash のサブコマンドであれば実現できます。標準でインストールされていることの多い screen の例を示します。

$ ssh REMOTEHOST "screen -dm -S qoosky bash -c './hello.sh > out.txt'"
  • -dm : デタッチされた状態で仮想端末を作成
  • -S : セッション名を指定 (任意)

検証してみます。

$ ssh REMOTEHOST "screen -ls"
There is a screen on:
        10602.qoosky (Detached)
1 Socket in /var/run/screen/S-ec2-user.

$ ssh REMOTEHOST "tailf out.txt"
2015年  6月 15日 月曜日 21:53:07 UTC
2015年  6月 15日 月曜日 21:53:08 UTC

プロセスの処理が完了すれば仮想端末は自動で消滅します。

$ ssh REMOTEHOST "screen -ls"
No Sockets found in /var/run/screen/S-ec2-user.

処理の完了を待たずに終了したい場合は以下のようにします。

$ ssh REMOTEHOST "screen -S qoosky -X quit"

nohup コマンドの場合と比較してプロセスが fork されている場合におけるシグナル耐性が高いように思われます。nohup でうまくいかない場合には利用を検討してみてください。

関連ページ
    「AWS IoT ボタン」を用いずにインターネット経由でスマホによるラジコン操作 スマートフォンから操作できるブルドーザーロボットです。前進、後退、回転が可能です。Qoosky WebSocket API を利用しています。制作費は Raspberry Pi が既に手元にあれば追加でおおよそ 1 万円です。センサー機能が搭載されていないため正確な操作はできませんが、学校や職場から自宅のロボットを
    概要 無限ループに陥ってしまったプロセスを強制終了させるためにはCtrl-Cやkillコマンドを利用しますね。このとき、プロセスにはシグナルというものが送られています。プロセスはシグナルの種類に応じて既定された処理を実行します。trapコマンドを用いると、各シグナル番号に対応する既定の処理を書き換えることができます。
    概要 電子工作や製品のプロトタイピング (例『地球規模で遠隔操作できるブルドーザー』) で利用される Raspberry Pi 3 について、こちらのページで構築した環境で Android Things アプリケーションを開発できます。 本ページでは、簡単な例として LED を点灯させるアプリケーションを扱います。より実用的なアプリケーションを開発する際には
    概要 よく使う python ライブラリのサンプルコード集です。 JSON #!/usr/bin/python # -*- coding: utf-8 -*- import json arr = [1, 2, {'xxx': 3}] # オブジェクト ←→ JSON 文字列 jsonStr = json.dumps(arr) arr2 = json.loads(jsonStr) # オ
    コマンドのエイリアスを登録する (update-alternatives) mybin という名前のコマンドを登録 sudo update-alternatives --install /usr/local/bin/mybin mybin /usr/bin/echo 10 sudo update-alternatives --install /usr/local/bin/mybin mybin