69

親プロセスが新しいサブプロセスを作成することに関連していると思いますが、tty はありません。ボンネットの下の詳細を説明できる人はいますか? つまり、関連する bash の作業モデル、プロセス作成などは?

非常に幅広いトピックになる可能性があるため、投稿へのポインタも非常に高く評価されます. 私はしばらくグーグルで検索しましたが、すべての結果は非常に具体的なケースに関するものであり、舞台裏の話に関するものはありません. より多くのコンテキストを提供するために、以下は「bash: no job control in this shell」という結果になるシェル スクリプトです。

#! /bin/bash

while [ 1 ]; do
    st=$(netstat -an |grep 7070 |grep LISTEN -o | uniq)
    if [ -z $st ]; then
        echo "need to start proxy @$(date)"
        bash -i -c "ssh -D 7070 -N user@my-ssh.example.com > /dev/null"
    else
        echo "proxy OK @$(date)"
    fi
    sleep 3
done

この行:

bash -i -c "ssh -D 7070 -N user@my-ssh.example.com > /dev/null"

「bash:no job control in this shell」の由来です。

4

5 に答える 5

54

ジョブ制御は、ユーザーが単一の対話型シェルから複数のジョブを管理できるようにするシェルと tty ドライバーの機能の集合です。

ジョブは、単一のコマンドまたはパイプラインです。実行する場合ls、それは仕事です。を実行するls|moreと、それはまだ 1 つのジョブにすぎません。実行するコマンドが独自のサブプロセスを開始する場合、意図的に切り離されない限り、それらも同じジョブに属します。

&ジョブ制御がなければ、コマンド ラインに追加することでジョブをバックグラウンドに置くことができます。そして、それはあなたが持っているすべてのコントロールについてです。

ジョブ制御を使用すると、さらに次のことができます。

  1. 実行中のフォアグラウンド ジョブを中断するCtrlZ
  2. 中断されたジョブをフォアグラウンドで再開するfg
  3. バックグラウンドでサスペンドジョブを再開するbg
  4. 実行中のバックグラウンド ジョブをフォアグラウンドに移動するfg

シェルは、コマンドを実行することで確認できるジョブのリストを維持しますjobs。それぞれにジョブ番号が割り当てられます (ジョブを構成するプロセスの PID とは異なります)。のプレフィックスが付いたジョブ番号を%引数として使用しfgたりbg、フォアグラウンドまたはバックグラウンドにするジョブを選択したりできます。%jobnumber 表記は、シェルの組み込みkillコマンドでも受け入れられます。ジョブ番号は 1 から割り当てられるため、PID よりも短いので便利です。

%+直前にフォアグラウンド化されたジョブと前にフォアグラウンド化されたジョブのショートカットもあるため、数字を覚えなくても (現在のジョブを一時停止し、別のジョブを再開) を実行%-することで、2 つのジョブをすばやく切り替えることができます。または、コマンド自体の先頭を使用できます。コマンドを一時停止した場合、それを再開するのは簡単です(他のアクティブなジョブが "ff" で始まるものではないことを前提としています)。最後のショートカットとして、. を入力する必要はありません。コマンドとして入力するだけで、前のジョブがフォアグラウンドになります。CtrlZfg %-ffmpegfg %fffg%-

「しかし、なぜこれが必要なのですか?」私はあなたが尋ねるのを聞くことができます。「別のコマンドを実行したい場合は、別のシェルを起動できます。」確かに、マルチタスクには多くの方法があります。通常の日に、ログイン シェルを tty1 から tty10 で実行しています (6 つ以上あります。アクティブ化する必要があります)。そのうちの 1 つは 4 つの画面で画面セッションを実行し、別のシェルでは ssh を実行している可能性があります。リモート マシンで実行されている別の screen セッションと、3 つまたは 4 つの xterm を使用した X セッションがあります。そして、私はまだジョブコントロールを使用しています。

viまたはlessまたはaptitudeまたは その他のインタラクティブな処理の途中で、他のいくつかのクイック コマンドを実行して続行方法を決定する必要がある場合CtrlZは、コマンドを実行しますfg。自然で迅速です。(多くの場合、対話型プログラムには!、外部コマンドを実行するためのキーバインドがあります。シェルの履歴、コマンド ライン エディター、および補完システムの利点が得られないため、これはあまり良くないと思います。)誰かが 2 番目の xterm/screen/whatever を起動して 1 つのコマンドを実行し、それを 2 秒間見てから終了するのを見るたびに悲しくなります。

さて、あなたのこのスクリプトについて。一般的に、それは有能に書かれているようには見えません。問題の行:

bash -i -c "ssh -D 7070 -N user@my-ssh.example.com > /dev/null"

紛らわしいです。ssh コマンドがメイン スクリプトから直接実行されるのではなく、別のシェルに渡される理由がわかりません-i。この-iオプションは、シェルに対話的に実行するように指示し、ジョブ制御を (とりわけ) 有効にします。しかし、実際にはインタラクティブに使用されていません。別のシェルと の背後にある目的が何であれ、-iジョブ制御に関する警告は副作用でした。sshの望ましくない機能を回避するためのハックだったと思います。それは、それを行うときにコメントする必要があるようなものです。

于 2012-08-06T07:54:15.290 に答える
23

考えられるオプションの 1 つは、tty にアクセスできないことです。

フードの下:

  1. bash は、セッションがインタラクティブかどうかをチェックします。そうでない場合は、ジョブ制御はありません。
  2. forced_interactive が設定されている場合、stderr が tty に接続されているかどうかのチェックがスキップされ、bash が/dev/tty読み書きアクセス用に開くことができるかどうかを再度チェックします。
  3. 次に、改行規則が使用されているかどうかを確認し、使用されていない場合は、ジョブ制御も無効になります。
  4. プロセス グループを pid に設定してプロセス グループ リーダーになり、ターミナルが (新しい) プロセス グループと同じプロセス グループにない場合 (およびその場合のみ)、ターミナルのプロセス グループを ( new) プロセス グループ。それが失敗した場合は、プロセス グループを元の状態に戻し (ターミナルから読み取ることができるように)、ジョブ制御をオフにします。
  5. 上記のすべてが失敗した場合は、メッセージが表示されます。

bash のソース コードからのコメントを部分的に引用しました。


質問の作成者の追加の要求に従って:

http://tiswww.case.edu/php/chet/bash/bashtop.htmlここに bash 自体があります。

C コードが読める場合は、ソース tarball を入手してくださいjob.c。その中には、「ボンネットの下」の詳細が説明されています。

于 2012-08-06T00:56:29.910 に答える
4

私自身の組み込みシステムで問題が発生し、「setsid」を使用して getty プロセスを実行することで「ジョブ制御なし」エラーを取り除きました。マンページによると、新しいセッション ID でプロセスを開始します。

于 2015-02-10T13:08:39.640 に答える