ターミナルからプロセスを完全にデタッチするにはどうすればよいですか?


304

UbuntuでTilda(ドロップダウンターミナル)を「コマンドセントラル」として使用します。他の人がGNOME Do、Quicksilver、Launchyを使用するのとほぼ同じ方法です。

ただし、起動元の端末からプロセス(Firefoxなど)を完全に切り離す方法に苦労しています。つまり、そのような(非)子プロセスを防ぐ

  • 発信元端末を閉じると終了します
  • STDOUT / STDERRを介して発信端末を「汚染」します

たとえば、「適切な」ターミナルウィンドウでVimを起動するために、次のような簡単なスクリプトを試しました。

exec gnome-terminal -e "vim $@" &> /dev/null &

ただし、それでも汚染の原因になります(また、ファイル名を渡しても機能しないようです)。


1
それも良い質問です。私はバッシュにプログラミング言語を考慮することが公正だと思う-確かにこの質問の範囲は、システム管理者側ではおそらくよりですが...

これは、この質問の重複であるstackoverflow.com/questions/285015/...
ダナセイン


ユースケースでは、完全な切り離しについては説明していません。
ジグガンジャー

回答:


344

まず第一に; プロセスを開始したら、最初に停止(ヒットCtrl- Zbgしてからバックグラウンドで再開できるように入力することで、バックグラウンドで実行できます。現在は「ジョブ」であり、そのstdout/ stderr/ stdinはまだ端末に接続されています。

プロセスの最後に「&」を追加すると、すぐにバックグラウンドでプロセスを開始できます。

firefox &

無音のバックグラウンドで実行するには、これを使用します:

firefox </dev/null &>/dev/null &

追加情報:

nohupは、代わりにstdout / stderrをファイルに送信でき、親スクリプトを閉じても子がSIGHUPしないようにアプリケーションを実行するために使用できるプログラムです。ただし、アプリケーションを開始する前にそれを使用するための先見性が必要です。方法のためのnohup作品は、あなただけではないことができ、実行中のプロセスに適用します

disownシェルのジョブリストからシェルジョブを削除するbashビルトインです。これは基本的に意味することは、使用できないことですfgbgもうそれではなく、もっと重要なのは、あなたがあなたのシェルを閉じたときに、それがハングアップしたり送信しませんSIGHUPもうその子に。とは異なりnohup、プロセスの起動とバックグラウンド化disown使用さます。

あなたは何をすることができないん、それを立ち上げた後、プロセスの標準出力/標準エラー出力/ STDINを変更です。少なくともシェルからは。プロセスを起動して、そのstdoutがターミナル(デフォルトで行うこと)であることを伝えると、そのプロセスはターミナルに出力するように構成されます。シェルは、プロセスのFDセットアップとは関係ありません。これは、プロセス自体が管理するものです。プロセス自体は、stdout / stderr / stdinを閉じるかどうかを決定できますが、シェルを使用して強制的に閉じることはできません。

バックグラウンドプロセスの出力を管理するには、スクリプトから多くのオプションがあります。「nohup」が最初に思い浮かぶでしょう。しかし、対話型プロセスを開始するが、沈黙するのを忘れたfirefox < /dev/null &>/dev/null &場合()、本当に多くのことを実行できません。

GNUを入手することをお勧めしますscreen。画面を使用すると、プロセスの出力が面倒になったときに実行中のシェルを閉じて、新しいシェルを開くことができます(^Ac)。


ああ、ところで、$@あなたがそれを使用しているところで「」を使用しないでください。

$@手段、$1$2$3...、にあなたのコマンドをオンにします:

gnome-terminal -e "vim $1" "$2" "$3" ...

-eは引数を1つしか受け取らないため、これはおそらく望んでいないことです。$1スクリプトが引数を1つしか処理できないことを示すために使用します。

シェルコマンド文字列である引数を1つしか受け取らないgnome-terminal -eため、()で指定したシナリオで複数の引数を適切に機能させるのは本当に困難-eです。引数を1つにエンコードする必要があります。最良かつ最も堅牢であるが、かなりぎこちない方法は次のとおりです。

gnome-terminal -e "vim $(printf "%q " "$@")"

これに感謝します!悲しいことに、私は1つの答えしか受け入れられません。最終的に「nohup $ @&> / dev / null&」と「alias wvim = 'launch.sh gnome-terminal -x vim'」

20
素晴らしく詳細で有益な答えです。+1
ティーキン

1
@ Hi-Angelは、インタラクティブなbashシェルを閉じると、bashがすべてのアクティブなジョブをHUPします。^ Zでプロセスをbgしても、それはまだ仕事です。それはバックグラウンドの仕事です。それをジョブとして削除するには、を使用disownします。bashはそれをHUPしなくなるため、シェルを閉じた後もプロセスは生き続けます。
lhunath

3
使用しません$*代わりに$@、すでに別の文字列の問題を解決?
sjas

2
できないことは、プロセスを起動した後にプロセスのstdout / stderr / stdinを変更することです。-正確にそうではありません。これに使用reptyrします。
ステファンザイデル

198
nohup cmd &

nohup プロセスを完全に切り離します(デーモン化します)


5
簡潔さは価値がありますが、完全性はより価値があります。nohupはGNU coreutilですが、ここではbashのみの回答(または存在しないことに注意)が適切です。それでも良い答えです。
限定償い

23
nohupSIGHUP信号を無視します。プロセスを正常に実行します。デーモン化なし。
ニモ

1
@nemoこれは、プロセスが切り離されていないことを意味しますがinit、シェルが終了した場合、切り離されます(およびの子)。
ノルドリン

@Noldorinはい。シェルの終了時に送信されるSIGHUPを無視すると、子プロセスは実行されたままになり、initに再配置されます。
ニモ

@nemo nohupは、標準の入出力も無音にします。完全に切り離すにはdisownでフォローアップします。
ジグガンジャー

60

使用している場合はbash、試してください。bash(1)を参照してください。disown [jobspec]

あなたが試すことができる別のアプローチはat nowです。スーパーユーザーでない場合、使用する許可atが制限される場合があります。


「disown」は内部bashコマンドではないようです(私のマシンでは使用できません。bashを使用しています)。「nohup」は、Benが提案したように、これを行うためのはるかに優れた(そして標準の)方法かもしれません。

1
「at」を使用することを考えたことがありません。アイデアをありがとう!
カドリアン

1
at他の誰かに実行を委任するために、私はそれが好きです!+1
忍水

1
参照点として、これzshも同様に機能します。
コーデラー

1
また、disown望みどおりの効果があるとは思われませんgnome-terminal- disown端末が終了すると、edプロセスはまだ強制終了されます。理由/方法を知りたいです。
カイルストランド

38

これらの答えを読んで、発行nohup <command> &するだけで十分だという最初の印象を受けました。gnome-terminalでzshを実行nohup <command> &すると、終了時にシェルが子プロセスを強制終了するのを防ぐことができませんでした。が、nohup特に非対話型シェルと、便利です、それが唯一の子プロセスがために、そのハンドラをリセットしない場合は、この動作を保証SIGHUP信号を。

私の場合、nohupハングアップ信号がアプリケーションに到達しないようにすべきでしたが、子アプリケーション(この場合はVMWare Player)がSIGHUPハンドラーをリセットしていました。その結果、ターミナルエミュレータが終了しても、サブプロセスが強制終了される可能性があります。私の知る限り、これはシェルのジョブテーブルからプロセスを確実に削除することによってのみ解決できます。場合によってnohupはシェルビルトインで上書きされる場合、これは十分ではありませんが、そうでない場合は...


disownシェルがで組み込みされbashzshおよびksh93

<command> &
disown

または

<command> &; disown

ワンライナーを好む場合。これには、ジョブテーブルからサブプロセスを削除するという一般的に望ましい効果があります。これにより、子プロセスに誤ってシグナルを送ることなく、ターミナルエミュレータを終了できます。SIGHUPハンドラがどのように見えても、これはあなたの子プロセスを殺すべきではありません。

否認後、プロセスは引き続きターミナルエミュレータの子になります(pstreeこれを実際に見たい場合はプレイしてください)が、ターミナルエミュレータが終了すると、initプロセスに接続されていることがわかります。言い換えれば、すべてが本来あるべき姿であり、おそらくあなたが望んでいるとおりです。

シェルがサポートしていない場合はどうしますdisownか?私は、そうするものに切り替えることを強く推奨しますが、そのオプションがない場合、いくつかの選択肢があります。

  1. screenそしてtmux、この問題を解決することができますが、彼らははるかに重い重量のソリューションであり、私はこのような単純なタスクのためにそれらを実行する必要が嫌い。これらは、通常リモートマシンでttyを維持したい状況により適しています。
  2. 多くのユーザーにとって、シェルがzshのような機能をサポートしているかどうかを確認することが望ましい場合がありますsetopt nohup。これはSIGHUP、シェルの終了時にジョブテーブル内のジョブに送信されないように指定するために使用できます。これは、シェルを終了する直前に適用するか、~/.zshrc常にオンにする場合のようにシェル構成に追加できます。
  3. ジョブテーブルを編集する方法を見つけます。tcshまたはcshでこれを行う方法が見つかりませんでしたが、これはやや気がかりです。
  4. 小さなCプログラムを書いてforkとforkしexec()ます。これは非常に貧弱なソリューションですが、ソースは数十行で構成する必要があります。その後、コマンドをコマンドライン引数としてCプログラムに渡すことができるため、ジョブテーブル内のプロセス固有のエントリを回避できます。

29
  1. nohup $COMMAND &
  2. $COMMAND & disown
  3. setsid command

私は非常に長い間2番を使用していますが、3番も同様に機能します。また、disownnohupフラグがあり-h、ですべてのプロセスを否認でき、で実行中のすべてのプロセスを-a否認できます-ar

サイレンシングはによって達成され$COMMAND &>/dev/nullます。

お役に立てれば!


短くて甘い。この非常に役立つ要約をありがとう!
シェルジョン

私はまだこの投稿の通知を受け取るとは信じられません...
ミント・フレッシュ

9

画面があなたの問題を解決するかもしれないと思う


9

tcsh(および他のシェルでも)で、括弧を使用してプロセスを切り離すことができます。

これを比較してください:

> jobs # shows nothing
> firefox &
> jobs
[1]  + Running                       firefox

これに:

> jobs # shows nothing
> (firefox &)
> jobs # still shows nothing
>

これにより、ジョブリストからfirefoxが削除されますが、ターミナルに関連付けられたままです。「ssh」を介してこのノードにログインした場合、ログアウトしようとするとsshプロセスがハングします。


9

bashの最もシンプルで唯一の正しい答え:

command & disown

端末からではなく、シェルからプロセスを切り離す必要はありません。


7

ttyシェルの関連付けを解除するには、サブシェルを介してコマンドを実行します(例:

(コマンド)&

出口が閉じられた端末を使用したが、プロセスがまだ生きているとき。

小切手 -

(sleep 100) & exit

他の端末を開く

ps aux | grep sleep

プロセスはまだ生きています。


これはまさに私が必要としたものです。(「は/ opt /崇高テキスト2 / sublime_textの」$ @)&:私は崇高なテキストのコンソールショートカットを追加しようとしていたし、それが完璧に動作しますが、ここで私がなってしまったものだ
ロンE

5

ジョブのバックグラウンド化とフォアグラウンド化は、おそらくすべてのUnixシステム管理者が知っておくべき最初の事柄の1つです。

bashを使用した方法は次のとおりです。

./script.sh
# suspend process
{ctrl-Z}
# background process
bg
# list all backgrounded jobs
jobs
# bring it back to foreground
fg

4

nohupコマンドを使用してコマンドを実行できます。これにより、プロセスが切り離され、出力が特定のファイルにリダイレクトされます...しかし、それがまさに必要なものかどうかはわかりません。


私はexecを使用する前にnohupを試したと断言できましたが、明らかに正しくありません。次のように機能します。nohup gnome-terminal -e "vim $ @"&> / dev / null&

2

デーモンを試してみてください-使いやすいパッケージマネージャーから入手でき、ターミナルから自分自身を切り離すあらゆる方法を包括的に処理する必要があります。


2

これをbashrc / zshrcに追加するだけです:

detach() {
  "$@" 1>/dev/null 2>/dev/null &; disown
}

その後、次のような紛らわしいコマンドを実行できます。

detach gedit ~/.zshrc

1

私の.bashrcには、まさにその目的のためにこれらの関数があります:

function run_disowned() {
    "$@" & disown
}

function dos() {
    # run_disowned and silenced

    run_disowned "$@" 1>/dev/null 2>/dev/null
}

dos端末から切り離して実行するコマンドのプレフィックスを付けます。

関数はで動作するように書かれているbashzsh


1
この回答では、ある関数を次のようなボディで使用するだけで十分な場合に、この回答が別の関数にラップされた関数を使用する理由について少し混乱しています ( "$@" & disown) &> /dev/null。また、使用することがあまりない理にかなっている1>2>、あなたが使用しているので、disownあなたはbashのを使用していることを意味する、とbashであなただけ簡単に行うことができます&>stdoutとstderrの両方をリダイレクトする
Sergiy Kolodyazhnyy

(1)この方法で読みやすいと思います。(2)run_disownedドットファイルの他の場所に機能が必要だからです。&>もちろん、あなたはそのことについて正しいです。
mic_e 16

0

Mac OS Xでは、nohupとdisownの両方を使用して、子プロセスが端末で破棄されないようにする必要があることがわかりました。


0

これを行うには、次のスクリプトを使用します。端末へのプロセスの印刷を停止し、でデタッチし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
>>>


-1

多くの回答がnohupの使用を提案しました。むしろpm2を使用することを勧めしますnohupではなくpm2を使用すると、アプリケーションを存続させたり、アプリケーションのログファイルを保持したり、その他の多くの機能を使用するなど、多くの利点があります。詳細については、こちらをご覧ください

pm2をインストールするには、npmをダウンロードする必要があります。Debianベースのシステムの場合

sudo apt-get install npm

Redhatの場合

sudo yum install npm

または、これらの指示に従うことができます。npmのインストール後、それを使用して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

1
UNIXプロセスを制御するためにNodeJSアプリケーションを使用する(nohupのような小さくて堅牢なコマンドに対して)のは...本当にやり過ぎであり、正直、むしろ奇妙です。再起動機能が必要な場合は、monitを使用します。
セルジオ

@Sergioは、depricatedアプリケーションを使用するあなたの選択です。
ハック

今年(4日前の1回)いくつかのリリースが行われているため、monitが非推奨のアプリケーションであると思われる理由がわかりません。@see mmonit.com/monit/changes
セルジオ

私はnohupについて話していました。
ハック

1
nohupは単純な標準POSIXコマンドであるため、同じコメント:非推奨ではありません。@see unix.com/man-page/posix/1p/nohup
セルジオ・

-1

ターミナルウィンドウを維持せずにコマンドラインアプリケーションを単純に起動することが目的の場合は、alt-F2でターミナルを起動してからアプリケーションを実行してみてください。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.