ターミナルからプロセスを完全に切り離すにはどうすればいいですか?
私は Ubuntu の Tilda (ドロップダウンターミナル) を「コマンドセンター」として使用しています。例えば、「適切な」ターミナルウィンドウで Vim を起動するために、次のような簡単なスクリプトを試してみました:
exec gnome-terminal -e "vim $@" &> /dev/null &
しかし、これでもまだ汚染を引き起こしています (また、ファイル名を渡してもうまくいかないようです)。
まず第一に、一度処理を開始したら、まず処理を停止して(Ctrl-Zを打つ)、bg
と入力してバックグラウンドで再開させることができます。これで「ジョブ」となり、そのstdout
/stderr
/stdin
はまだターミナルに接続されています。
最後に"&“をつけることで、すぐにバックグラウンドでプロセスを開始することができます:
firefox &
無音でバックグラウンドで実行するには、これを使用してください:
firefox </dev/null &>/dev/null &
いくつかの追加情報です。
nohup
は、アプリケーションを実行するのに***を使うことができるプログラムです。しかし、アプリケーションを起動する前にこれを使用する先見の明が必要です。
nohup
はシェルのジョブリストからシェルのジョブを削除する bash ビルトインです。これが基本的に意味するのは、disown
, fg
をその子に使えなくなったということですが、もっと重要なことは、シェルを閉じたときにハングしたり、その子にbg
を送ったりしなくなったということです。SIGHUP
とは異なり、nohup
はプロセスが起動されてバックグラウンド化された**後に使用されます。
できないことは、プロセスを起動した後にプロセスの標準出力/stderr/stdin を変更することです。少なくともシェルからはできません。プロセスを起動して、その標準出力をターミナルに設定した場合 (デフォルトではそうなっています)、そのプロセスはターミナルに出力されるように設定されています。シェルはプロセスの FD 設定とは何の関係もありません。プロセス自身は、stdout/stderr/stdin を閉じるかどうかを決めることができますが、シェルを使って強制的に閉じさせることはできません。
バックグラウンドプロセスの出力を管理するには、スクリプトから多くのオプションがあります。しかし、起動しているのに黙らせるのを忘れてしまった対話的なプロセス (disown
) には、あまり何もできません。screen を使えば、プロセスの出力が面倒になったら実行中のシェルを閉じて、新しいシェルを開くことができます (
あ、ちなみに ”firefox < /dev/null &>/dev/null &
“ は使うところでは使わないでください。
screen
は、^Ac
, $@
, $@
, $1
…という意味で、以下のようになります。
あなたが与えた($2
を使った)シナリオでは、複数の引数を適切に動作させるのは本当に難しいです。引数を一つにエンコードしなければなりません。最良で最も堅牢な方法は、以下のようになります:
gnome-terminal -e "vim $1" "$2" "$3" ...
もし、bash
を使っているのであれば、disown [jobspec]
を試してみてください; bash(1) を参照してください。スーパーユーザでない場合、at now
の使用許可が制限されている可能性があります。
これらの回答を読んで、私は最初、nohup <command> &
を発行すれば十分だと思っていました。gnome-terminal で zsh を実行してみると、nohup <command> &
はシェルが終了時に子プロセスを kill するのを防いでいないことがわかりました。nohup
は特に非インタラクティブなシェルでは便利ですが、この動作を保証するのは、子プロセスが SIGHUP
シグナルのハンドラをリセットしない場合だけです。
私の場合、nohup
はハングアップシグナルがアプリケーションに到達するのを防ぐはずでしたが、子アプリケーション (この場合は VMWare Player) は SIGHUP
ハンドラをリセットしていました。その結果、ターミナルエミュレータが終了したときに、まだあなたのサブプロセスを殺すことができました。これは、私の知る限りでは、シェルのジョブテーブルからプロセスを削除することによってのみ解決できます。nohup
がシェルの組み込み関数でオーバーライドされている場合、時々そうであるように、これは十分かもしれませんが、そうでない場合には…
disown
はシェルの組み込み関数で、bash
, zsh
, ksh93
,
<command> &
disown
または
<command> &; disown
のように、ワンライナーを好む場合には、
&001
です。これは、ジョブテーブルからサブプロセスを削除するという一般的に望ましい効果を持っています。これにより、誤って子プロセスに全くシグナルを出さずにターミナルエミュレータを終了することができます。SIGHUP
ハンドラがどのように見えようとも、これは子プロセスを殺してはいけません。
disown の後、プロセスはまだターミナルエミュレータの子プロセスですが(これを動作中に見たい場合は pstree
で遊んでください)、ターミナルエミュレータが終了した後、init プロセスに接続されているのを見るべきです。言い換えれば、すべてがあるべき姿であり、おそらくあなたが望んでいる通りになっているということです。
disown
と screen
はこの問題を解決することができますが、それらは非常に重く、このような単純なタスクのためにそれらを実行するのは嫌です。これらは、一般的にリモートマシン上で tty をメンテナンスしたい場合には、より適しています。多くのユーザにとって、シェルが zsh の tmux
のような機能をサポートしているかどうかを確認することが望ましいかもしれません。これは、シェルが終了するときにジョブテーブルのジョブに setopt nohup
を送信しないように指定するために使うことができます。シェルを終了する直前にこれを適用するか、常に有効にしておきたい場合は SIGHUP
のようにシェルの設定に追加することができます。ジョブテーブルを編集する方法を探す。これをする方法が~/.zshrc
やtcsh
では見つけられなかったので、少々気になるところです。フォークオフする小さなC言語のプログラムを書いてcsh
。これは非常に貧弱な解決策ですが、ソースは数十行で構成されているはずです。そうすれば、コマンドをコマンドラインの引数として C プログラムに渡すことができるので、ジョブテーブルのプロセス固有のエントリを避けることができます。nohup $COMMAND &
$COMMAND & disown
setsid command
私は2番をずっと使ってきましたが、3番でも同様に動作します。また、disown
はnohup
のフラグを持っていて、-h
ですべてのプロセスをdisownすることができ、-a
で実行中のすべてのプロセスをdisownすることができます。
サイレンシングは-ar
によって達成されます。
bashの最もシンプルで唯一の正解:
command & disown
ターミナルからプロセスを切り離す必要はありませんが、シェルから切り離す必要はありません。
これは、ジョブリストから firefox を削除しますが、まだターミナルに縛られています。
これを bashrc/zshrc に追加します:
detach() {
"$@" 1>/dev/null 2>/dev/null &; disown
}
そうすれば、以下のように勘当されたコマンドを実行することができます:
detach gedit ~/.zshrc
これを行うために以下のスクリプトを使用しています。端末への印刷処理を停止し、nohup
で切り離し、TIMEOUT
内でコマンドが終了するとリターンステータスで終了します。 使用例:
#!/bin/bash
TIMEOUT=0.1
CMD=( "$@" )
#Could have some shortcuts here, e.g. replace "somefile.c" with "gedit somefile.c"
#use nohup to run the command, suppressing its output and allowing the terminal to be closed
#also send nohup's output to /dev/null, supressing nohup.out
#run nohup in the background so this script doesn't block
#print the command for debugging and to see bash variable expansion
printf "%q " "${CMD[@]}"
echo
nohup "${CMD[@]}" >/dev/null 2>&1 &
NOHUP_PID=$!
#kill this script after a short time, exiting with success status - command is still running
#this is needed as there is no timeout argument for `wait` below
MY_PID=$$
trap "exit 0" SIGINT SIGTERM
sleep $TIMEOUT && kill $MY_PID 2>/dev/null & #ignore "No such process" error if this exits normally
#if the command finishes before the above timeout, everything may be just fine or there could have been an error
wait $NOHUP_PID
NOHUP_STATUS=$?
#print an error if there was any. most commonly, there was a typo in the command
[$NOHUP_STATUS != 0] && echo "Error: $CMD"
#return the exit status of nohup, whatever it was
exit $NOHUP_STATUS
>>> run false
false
Error: false
>>> echo $?
1
>>> run true
true
>>> run sleep 10
sleep 10
>>>
多くの回答は nohup を使うことを提案しています。私はむしろ pm2 を使うことを提案します。nohupよりもpm2_を使うことで、アプリケーションを生きたまま維持したり、アプリケーションのログファイルを管理したり、他にも多くの利点があります。詳細は check this out .
pm2 をインストールするには npm をダウンロードする必要があります。Debian ベースのシステムのために
sudo apt-get install npm
と Redhat のために
sudo yum install npm
またはあなたは これらの指示 に従うことができます。npm_ をインストールした後、それを使用して pm2 をインストールするために pm2
npm install pm2@latest -g
一度それが行われたら、
$ pm2 start app.js # Start, Daemonize and auto-restart application (Node)
$ pm2 start app.py # Start, Daemonize and auto-restart application (Python)
によってアプリケーションを起動することができますプロセスの監視のために次のコマンドを使用します:
$ pm2 list # List all processes started with PM2
$ pm2 monit # Display memory and cpu usage of each app
$ pm2 show [app-name] # Show all informations about application
アプリ名またはプロセス ID を使用してプロセスを管理するか、またはすべてのプロセスを一緒に管理します:
$ pm2 stop <app_name|id|'all'|json_conf>
$ pm2 restart <app_name|id|'all'|json_conf>
$ pm2 delete <app_name|id|'all'|json_conf>
ログファイルは
$HOME/.pm2/logs #contain all applications logs
で見つけることができます。