web-dev-qa-db-ja.com

ターミナルからプロセスを完全に切り離すにはどうすればよいですか?

私はUbuntuのTilda(ドロップダウンターミナル)を私の「コマンドの中心」として使っています - 他の人がGNOME Do、Quicksilver、Launchyを使うのと同じ方法です。

しかし、私はそれが起動されている端末からプロセス(例えばFirefox)を完全にデタッチする方法に苦労しています - すなわちそのような(非)子プロセスを防ぐ

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

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

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

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

299
AnC

まず第一に;プロセスを開始したら、最初に停止してバックグラウンド設定することができます(ヒット Ctrl - Z)と入力して、バックグラウンドで再開するためにbgを入力します。これは「ジョブ」になり、stdout/stderr/stdinはまだ端末に接続されています。

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

firefox &

沈黙させてバックグラウンドで実行するには、これを使用します。

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

いくつかの追加情報:

Nohupは、標準のstdout/stderrを代わりにファイルに送ることができ、親スクリプトを閉じても子が見えなくなるように、アプリケーションを実行するためにを使用できるプログラムです。ただし、アプリケーションを起動する前にそれを使用するための先見の明がある必要があります。 Nohupが機能する方法のため、実行中のプロセスにそれを適用することはできません。

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

あなたができないのは、起動後にプロセスの標準出力/標準エラー/標準入力を変更することです。少なくともシェルからではありません。あなたが自分のプロセスを起動し、その標準出力があなたの端末であると言うなら(これはあなたがデフォルトで行うことです)、そのプロセスはあなたの端末に出力するように設定されます。あなたのShellはプロセスのFD設定とは関係がありません。それは純粋にプロセス自体が管理するものです。プロセス自体がその標準出力/標準エラー出力/標準終了を閉じるかどうかを決めることができますが、シェルで強制的に閉じることはできません。

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

GNU screenを取得することをお勧めします。 screenを使うと、プロセスの出力が邪魔になって新しいシェル(^Ac)を開くときに実行中のシェルを閉じることができます。


おお、そしてところで、あなたがそれを使っているところで "$@"を使わないでください。

$@は、$1$2$3 ...を意味します。これにより、コマンドは次のようになります。

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

-eはone引数だけを取るので、おそらくそれはあなたが望むものではありません。スクリプトが1つの引数しか処理できないことを示すには、$1を使用します。

gnome-terminal -eは1つの引数(シェルコマンド文字列)のみを取るため、(-eを使用して)与えたシナリオで複数の引数を正しく機能させることは本当に困難です。あなたはあなたの議論を一つにエンコードしなければならないでしょう。最善かつ最も堅牢な、しかしかなりまとまった方法は、次のとおりです。

gnome-terminal -e "vim $(printf "%q " "$@")"
335
lhunath
Nohup cmd &

Nohup プロセスを完全にデタッチ(デーモン化)

198
dsm

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

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

59
Randy Proctor

これらの答えを読んで、私はNohup <command> &を出すことで十分であるという最初の印象の下にありました。 gnome-terminalでzshを実行しても、Nohup <command> &はシェルが終了時に子プロセスを強制終了するのを妨げないことがわかりました。 Nohupは特に非対話型シェルでは便利ですが、子プロセスがSIGHUPシグナルのハンドラをリセットしない場合にのみ、この動作が保証されます。

私の場合、Nohupはハングアップシグナルがアプリケーションに届かないようにするべきでしたが、子アプリケーション(この場合はVMWare Player)はSIGHUPハンドラをリセットしていました。その結果、端末エミュレータが終了しても、サブプロセスが終了する可能性があります。私の知る限りでは、プロセスがシェルのjobsテーブルから削除されていることを確認することによってのみ、これを解決できます。 NohupがShellの組み込み関数で上書きされる場合もありますが、そうでない場合はこれで十分な場合があります。


disownは、bashzsh、およびksh93に組み込まれたシェルです。

<command> &
disown

または

<command> &; disown

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

表示されなくなった後も、プロセスはターミナルエミュレータの子です(実際にこれを見たい場合はpstreeで遊んでください)が、ターミナルエミュレータの終了後はinitプロセスにアタッチされているはずです。言い換えれば、すべてはそれがあるべき姿であり、あなたがおそらくそれがありたいことなのです。

あなたのシェルがdisownをサポートしていない場合はどうしますか?私は強くすることを強く勧めますが、その選択肢がなければ、あなたにはいくつかの選択肢があります。

  1. screentmuxはこの問題を解決することができますが、それらははるかに重い解決策であり、私はそのような単純なタスクのためにそれらを実行しなければならないのが嫌いです。これらは、通常はリモートマシン上でttyを管理したい状況に非常に適しています。
  2. 多くのユーザーにとって、あなたのシェルがzshのsetopt Nohupのような機能をサポートしているかどうかを見ることは望ましいかもしれません。これは、シェルの終了時にSIGHUPをjobsテーブル内のジョブに送信しないように指定するために使用できます。シェルを終了する直前にこれを適用することも、常にオンにしたい場合は~/.zshrcなどのシェル構成に追加することもできます。
  3. Jobsテーブルを編集する方法を見つけてください。 tcshcshでこれを行う方法を見つけることができませんでしたが、これはやや厄介です。
  4. 分岐してexec()とする小さなCプログラムを書いてください。これは非常に貧弱な解決策ですが、ソースは数十行で構成されるべきです。そうすれば、Cプログラムにコマンドライン引数としてコマンドを渡すことができるため、jobsテーブルにプロセス固有のエントリを追加する必要がなくなります。
38
Stephen Rosen
  1. Nohup $COMMAND &
  2. $COMMAND & disown
  3. setsid command

私は長い間2番を使ってきましたが、3番も同じように機能します。また、disownには-hNohupフラグがあり、-aですべてのプロセスを却下し、-arで実行中のすべてのプロセスを却下できます。

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

お役に立てれば!

26
Mr. Minty Fresh

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

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

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

これに:

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

これは仕事のリストからFirefoxを削除しますが、それはまだ端末に結び付けられています。このノードに 'ssh'でログインした場合、ログアウトしようとしてもsshプロセスはハングします。

9
Nathan Fellman

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

9
dunkyp

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

command & disown

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

8
ManuelSchneid3r

Ttyシェルの関連付けを解除するには、サブシェルからコマンドを実行します。

(コマンド)&

終了時に端末が閉じられましたが、プロセスはまだ生きています。

チェック -

(sleep 100) & exit

他の端末を開く

ps aux | grep sleep

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

7
jitendra

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

これがbashで行われる方法です:

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

あなたは、Nohupコマンドを使ってあなたのコマンドを実行することができます、これはあなたのプロセスをデタッチし、与えられたファイルに出力をリダイレクトします...しかし、私はそれがまさにあなたが必要とするものではありません..

4
Ben

試す daemon - あなたのフレンドリーなパッケージマネージャから利用可能で、端末からそれ自身を分離するあらゆる方法を包括的に世話するべきです。

2
ShiDoiSi

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

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

それから、あなたはこのような卑劣なコマンドを実行することができます。

detach gedit ~/.zshrc
2
B. Branchard

私の.bashrcでは、私はまさにその目的のためにこれらの関数を持っています:

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

function dos() {
    # run_disowned and silenced

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

コマンドを端末から切り離して実行するには、コマンドの前にdosを付けます。

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

1
mic_e

私はMac OS X上で、子プロセスが端末で破壊されないようにするために、Nohupとdisownの両方を使用する必要があることを発見しました。

0
aaron

これを行うには、次のスクリプトを使用します。コマンドが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
>>>
0
jozxyqk

Sudo apt install ucommon-utils

pdetach command

そこに行きます:)

0
DarkAngel