nohup コマンドに問題があります。
ジョブを実行すると、大量のデータが生成されます。出力 nohup.out が大きくなりすぎて、プロセスが遅くなります。nohup.out を取得せずにこのコマンドを実行するにはどうすればよいでしょうか?
ベストアンサー1
このコマンドは、出力が端末に送信される場合にnohup
のみ書き込みます。コマンドの出力を他の場所 (を含む) にリダイレクトした場合は、代わりにそこに送信されます。nohup.out
/dev/null
nohup command >/dev/null 2>&1 # doesn't create nohup.out
ほとんどのシェル (ただしすべてではない) では、>/dev/null 2>&1
シーケンスは just に短縮できることに注意してください。>&/dev/null
を使用している場合は、全体の最後にnohup
別の を配置して、コマンドをバックグラウンドで実行する必要があることを意味します。&
nohup command >/dev/null 2>&1 & # runs in background, still doesn't create nohup.out
Linux では、ジョブを で実行すると、nohup
その入力も自動的に閉じられます。他のシステム、特に BSD と macOS ではそうではないため、バックグラウンドで実行しているときは、入力を手動で閉じる必要があるかもしれません。入力を閉じても の作成には影響しませんがnohup.out
、別の問題が回避されます。バックグラウンド プロセスがまだ開いている標準入力から何かを読み取ろうとすると、一時停止して、フォアグラウンドに戻って何かを入力するまで待機します。したがって、さらに安全なバージョンは次のようになります。
nohup command </dev/null >/dev/null 2>&1 & # completely detached from terminal
ただし、これによってコマンドが直接端末にアクセスするのが妨げられるわけではなく、シェルのプロセス グループから削除されるわけでもありません。後者を実行したい場合、bash、ksh、または zsh を実行している場合は、disown
次のコマンドとして引数なしで を実行することで実行できます。これにより、バックグラウンド プロセスはシェルの「ジョブ」に関連付けられなくなり、シェルからシグナルが転送されなくなります。( disown
ed プロセスは、親シェルから自動的にシグナルを転送されませんが、 がない場合、手動コマンドなどの他の手段で送信されたシグナルnohup
は受信します。 'ed プロセスは、送信方法に関係なく、すべてのシグナルを無視します。)HUP
kill
nohup
HUP
説明:
Unix システムでは、入力元または出力先にはそれぞれ「ファイル記述子」または略して「fd」と呼ばれる番号が関連付けられています。実行中のプログラム (「プロセス」) にはそれぞれ独自のファイル記述子のセットがあり、新しいプロセスが起動すると、そのうちの 3 つがすでに開かれています。「標準入力」である fd 0 はプロセスが読み取るために開かれ、「標準出力」(fd 1) と「標準エラー」(fd 2) はプロセスが書き込むために開かれます。ターミナル ウィンドウでコマンドを実行すると、デフォルトでは、入力したものはすべて標準入力に送られ、標準出力と標準エラーの両方がそのウィンドウに送信されます。
ただし、コマンドを起動する前に、シェルにこれらのファイル記述子の一部またはすべてが指す場所を変更するように要求することができます。これが、リダイレクト ( 、、、<
)演算子とパイプ ( ) 演算子の機能です。<<
>
>>
|
パイプは、これらのうち最も単純なものです。command1 | command2
の標準出力が のcommand1
標準入力に直接入力されるようにしますcommand2
。 これは、UNIX ツールの特定の設計パターンにつながった非常に便利な配置です (また、標準エラーの存在を説明しています。標準エラーにより、プログラムは、パイプライン内の次のプログラムに出力が送られている場合でも、ユーザーにメッセージを送信できます)。 ただし、パイプできるのは標準出力から標準入力までです。何らかの操作を行わないと、他のファイル記述子をパイプに送信することはできません。
リダイレクト演算子は、リダイレクトするファイル記述子を指定できる点でより使いやすいです。したがって、 は0<infile
という名前のファイルから標準入力を読み取りinfile
、 は2>>logfile
という名前のファイルの末尾に標準エラーを追加しますlogfile
。数値を指定しない場合、入力リダイレクトはデフォルトで fd 0 (<
と同じ0<
) になり、出力リダイレクトはデフォルトで fd 1 (>
と同じ1>
) になります。
また、ファイル記述子を組み合わせることもできます。2>&1
これは、「標準出力が送信される場所に標準エラーを送信する」ことを意味します。つまり、標準出力と標準エラーが混在した単一の出力ストリームが得られ、それらを分離できなくなりますが、パイプに標準エラーを含めることができることも意味します。
したがって、このシーケンスは>/dev/null 2>&1
、「標準出力を/dev/null
(書き込んだものをすべて破棄する特別なデバイス)に送信し、標準エラーを標準出力の送信先に送信する」( であることを確認しました/dev/null
)ことを意味します。基本的には、「このコマンドがいずれかのファイル記述子に書き込んだものをすべて破棄する」ということです。
nohup
は、標準エラーも出力も端末に接続されていないことを検出すると、 を作成nohup.out
せず、出力がすでにユーザーの希望する場所にリダイレクトされているものと想定します。
この/dev/null
デバイスは入力にも機能します。 でコマンドを実行すると</dev/null
、そのコマンドが標準入力から読み取ろうとすると、すぐにファイルの終わりに遭遇します。マージ構文はここでは同じ効果を持たないことに注意してください。これは、同じ方向 (入力または出力) で開かれている別のファイル記述子を指すためにのみ機能します。シェルでは を実行できます>/dev/null <&1
が、出力ストリームで開かれた入力ファイル記述子を持つプロセスが作成されるため、ファイルの終わりに遭遇する代わりに、読み取りを試みると致命的な「無効なファイル記述子」エラーが発生します。
Gwangmu Lee さんの質問に答えると、 には魔法はありません。nohup
なぜなら、 はシェル組み込みコマンドですらないからです (少なくとも bash と zsh には組み込みコマンドがありません。ksh には組み込みコマンドがあり、これを使用して他のシェル組み込みコマンドを実行できます)。どのコマンドでも、開いているファイル記述子が端末を指しているかどうかを確認できます。これは、ファイルを書き込むかどうかを決定するために行われることのすべてですnohup.out
。
リダイレクトを行う組み込みのシェル コマンドはありません。これは常に明示的に制御する必要があります。これは、暗黙的なリダイレクトを持つコマンドに明示的なリダイレクトを追加すると混乱が生じるためだと思います。ただし、独自のスクリプトや関数でリダイレクトを行うことを妨げるものは何もありません。たとえば、次のようになります。
run_detached() {
nohup "$@" </dev/null >/dev/null 2>&1 &
disown
}