web-dev-qa-db-ja.com

シェルからアプリケーションを「正しく」起動する方法

質問を正確に表現するのは難しいと思いますが、最善を尽くします。私はdwmをデフォルトのウィンドウマネージャーとして使用し、dmenuをアプリケーションランチャーとして使用しています。ブラウザ以外のGUIアプリケーションはほとんど使用していません。私の作業のほとんどは、コマンドラインから直接行われます。さらに、私はオペレーティングシステム、アプリケーションなどに関するミニマリズムの大ファンです。私が取り除くことができなかったツールの1つは、アプリケーションランチャーでした。主な理由は、アプリケーションランチャーがどのように動作するか/何をするかについての正確な理解がないためです。広範なインターネット検索でさえ、あいまいな説明しか表示されません。私がしたいのは、実際にアプリケーションを起動する以外はまったく使用しないため、アプリケーションランチャーも削除することです。これを行うために、シェルからアプリケーションを「正しく」起動する方法を本当に知りたいのです。これにより、「正しく」の意味は、「アプリケーションランチャーのように」と概算できます。十分に理解していないため、すべてのアプリケーションランチャーが同じように動作するとは主張していません。

シェルからプロセスを起動する次の方法について知っています。

  1. exec /path/to/Program新しいプロセスを作成せずに、指定したコマンドでシェルを置き換えます
  2. sh -c /path/to/Program起動シェル依存プロセス
  3. /path/to/Program起動シェル依存プロセス
  4. /path/to/Program 2>&1 &シェルに依存しないプロセスを起動する
  5. Nohup /path/to/Program &シェルに依存しないプロセスを起動し、出力をNohup.outにリダイレクトします

更新1:例を示します。 dmenuは、さまざまな条件下でps -eflを繰り返し呼び出して再構築します。新しいシェル/bin/bashを生成し、このシェルの子としてアプリケーション/path/to/Programを生成します。子供がそこにいる限り、シェルは周りにいます。 (これをどのように管理するかは私を超えています...)対照的に、シェルからNohup /path/to/Program &を発行すると/bin/bashになると、プログラムはこのシェルの子になりますが、このシェルを終了すると、プログラムの親は最上位のプロセスです。つまり、最初のプロセスが/sbin/init verbosePPID 1がある場合は、プログラムの親になります。グラフを使用して説明しようとしたものは次のとおりです。chromiumdmenuを介して起動され、firefoxexec firefox & exitを使用して起動されました。

systemd-+-acpid
        |-bash---chromium-+-chrome-sandbox---chromium-+-chrome-sandbox---nacl_helper
        |                 |                           `-chromium---5*[chromium-+-{Chrome_ChildIOT}]
        |                 |                                                    |-{Compositor}]
        |                 |                                                    |-{HTMLParserThrea}]
        |                 |                                                    |-{OptimizingCompi}]
        |                 |                                                    `-3*[{v8:SweeperThrea}]]
        |                 |-chromium
        |                 |-chromium-+-chromium
        |                 |          |-{Chrome_ChildIOT}
        |                 |          `-{Watchdog}
        |                 |-{AudioThread}
        |                 |-3*[{BrowserBlocking}]
        |                 |-{BrowserWatchdog}
        |                 |-5*[{CachePoolWorker}]
        |                 |-{Chrome_CacheThr}
        |                 |-{Chrome_DBThread}
        |                 |-{Chrome_FileThre}
        |                 |-{Chrome_FileUser}
        |                 |-{Chrome_HistoryT}
        |                 |-{Chrome_IOThread}
        |                 |-{Chrome_ProcessL}
        |                 |-{Chrome_SafeBrow}
        |                 |-{CrShutdownDetec}
        |                 |-{IndexedDB}
        |                 |-{LevelDBEnv}
        |                 |-{NSS SSL ThreadW}
        |                 |-{NetworkChangeNo}
        |                 |-2*[{Proxy resolver}]
        |                 |-{WorkerPool/1201}
        |                 |-{WorkerPool/2059}
        |                 |-{WorkerPool/2579}
        |                 |-{WorkerPool/2590}
        |                 |-{WorkerPool/2592}
        |                 |-{WorkerPool/2608}
        |                 |-{WorkerPool/2973}
        |                 |-{WorkerPool/2974}
        |                 |-{chromium}
        |                 |-{extension_crash}
        |                 |-{gpu-process_cra}
        |                 |-{handle-watcher-}
        |                 |-{inotify_reader}
        |                 |-{ppapi_crash_upl}
        |                 `-{renderer_crash_}
        |-2*[dbus-daemon]
        |-dbus-launch
        |-dhcpcd
        |-firefox-+-4*[{Analysis Helper}]
        |         |-{Cache I/O}
        |         |-{Cache2 I/O}
        |         |-{Cert Verify}
        |         |-3*[{DOM Worker}]
        |         |-{Gecko_IOThread}
        |         |-{HTML5 Parser}
        |         |-{Hang Monitor}
        |         |-{Image Scaler}
        |         |-{JS GC Helper}
        |         |-{JS Watchdog}
        |         |-{Proxy R~olution}
        |         |-{Socket Thread}
        |         |-{Timer}
        |         |-{URL Classifier}
        |         |-{gmain}
        |         |-{localStorage DB}
        |         |-{mozStorage #1}
        |         |-{mozStorage #2}
        |         |-{mozStorage #3}
        |         |-{mozStorage #4}
        |         `-{mozStorage #5}
        |-gpg-agent
        |-login---bash---startx---xinit-+-Xorg.bin-+-xf86-video-inte
        |                               |          `-{Xorg.bin}
        |                               `-dwm-+-dwmstatus
        |                                     `-xterm---bash-+-bash
        |                                                    `-pstree
        |-systemd---(sd-pam)
        |-systemd-journal
        |-systemd-logind
        |-systemd-udevd
        |-wpa_actiond
        `-wpa_supplicant

更新2:質問は次のように要約できると思います:プロセスの親は何であるべきですか?それは例えばシェルであるか、それともinitプロセス、つまりPID 1のプロセスである必要がありますか?

21
lord.garbage

まあ、あなたはそれをかなりよく理解しているようです。あなたが持っているもののいくつかを明確にするために、

  • _sh -c /path/to/Program_は、

    ドル sh
    % / path/to/Program
    % Ctrl+D(または、「出口」)

    ここで、新しいシェルプロセスを開始し、新しいシェルへのアプリケーションコマンドパスを指定して、新しいシェルを終了させます。説明のために、新しいシェルが異なるプロンプトを表示することを示しました。これはおそらく現実には起こりません。 _sh -c "command"_コンストラクトは、複数のコマンドをバンドルにラップするなどのトリッキーな処理を行うのに最も役立ちます。そのため、それらは単一のコマンド(使い捨ての名前のないスクリプトの一種)のように見える、またはシェル変数からの複雑なコマンドを作成する。単純な引数で単一のプログラムを実行するためだけに使用することはほとんどありません。

  • _2>&1_は、標準エラーを標準出力にリダイレクトすることを意味します。これは実際には_&_とはあまり関係ありません。むしろ、_command > file_と言い、エラーメッセージをファイルにキャプチャする場合でも、コマンドがエラーメッセージを画面に送信するときに使用します。
  • 出力を_Nohup.out_にリダイレクトすることは、Nohupの簡単な副作用です。 _Nohup command &_の主な目的は、_command_を非同期で実行して(一般に「バックグラウンドで」または「シェルに依存しないプロセス」として知られ、単語を使用する)、それを構成してより良いコマンドの実行中にシェルを終了すると(ログアウトなど)、実行を継続できる可能性があります。

bash(1) および Bashリファレンスマニュアル は、優れた情報源です。

プログラムを実行して端末から切り離す方法はいくつかあります。 1つは、バックグラウンドで実行することですサブシェルののように(firefoxをお好みのプログラムに置き換えます):

(firefox &)

もう1つは、プロセスを否認することです。

firefox & disown firefox

アプリランチャーの動作に興味がある場合は、dmenuが1つのバイナリスクリプトと2つのシェルスクリプト(それぞれdmenudmenu_pathdmenu_run)を提供します。

dmenu_runは、dmenu_pathの出力をdmenuにパイプします。dmenuは、$Shell変数が設定されているものにパイプします。空の場合は、/bin/shを使用します。

#!/bin/sh
dmenu_path | dmenu "$@" | ${Shell:-"/bin/sh"} &

dmenu_pathは少し複雑ですが、$PATH環境変数にバイナリのリストを提供し、可能であればキャッシュを使用します。

#!/bin/sh
cachedir=${XDG_CACHE_HOME:-"$HOME/.cache"}
if [ -d "$cachedir" ]; then
        cache=$cachedir/dmenu_run
else
        cache=$HOME/.dmenu_cache # if no xdg dir, fall back to dotfile in ~
fi
IFS=:
if stest -dqr -n "$cache" $PATH; then
        stest -flx $PATH | sort -u | tee "$cache"
else
        cat "$cache"
fi

シェルでプログラムを実行する必要はありません。シェルにパイプすることなくdmenu_runを記述する別の方法は次のとおりです。

#!/bin/sh
$(dmenu_path | dmenu "$@") &
11
gnucchi

G-Manの答えがとても好きです。しかし、私はあなたが懸念を混乱させていると思うので対応します。ウェインが指摘するように、最良の答えは「あなたが望む結果を得るものは何でも」です。

Unixプロセス管理では、すべてのプロセスに親があります。これの1つの例外は、ブート時にOSによって開始されるinitプロセスです。親プロセスが停止したときに、親プロセスがすべての子プロセスをそれと一緒に取るのは正常な動作です。これは、SIGHUPシグナルをすべての子プロセスに送信することによって行われます。 SIGHUPのデフォルト処理はプロセスを終了します。

ユーザープロセスのシェル生成は、選択した言語で fork(2) / exec(3) 呼び出しをコーディングした場合と同じです。シェルは親であり、シェルが終了した場合(たとえば、ユーザーがログオフした場合)、シェルが生成する子プロセスはそれに伴って進みます。あなたが説明するニュアンスは、その振る舞いを修正するための単なる方法です。

exec /path/to/programexec(3) を呼び出すようなものです。はい、それはあなたのシェルをprogramに置き換え、どんな親もシェルを起動したままにします。

sh -c /path/to/programは、programの子プロセスを作成する子シェルプロセスを無意味に作成します。 /path/to/programは実際には一連のスクリプト命令であり、実行可能ファイルではありません。 (sh /path/to/script.shを使用して、下位シェルでの実行権限のないシェルスクリプトを実行できます)

/path/to/programは「フォアグラウンド」プロセスを作成します。つまり、シェルはプロセスが完了するのを待ってから、他のアクションを実行します。システムコールのコンテキストでは、 fork(2) / exec(3) / waitpid(2) のようになります。子は親からstdin/stdout/stderrを継承することに注意してください。

/path/to/program &(リダイレクトを無視)は、「バックグラウンドプロセス」を作成します。プロセスはまだシェルの子ですが、親はプロセスが終了するのを待っていません。

Nohup /path/to/programは、制御端末が閉じている場合に Nohup(1) を呼び出して、SIGHUPがprogramに送信されないようにします。フォアグラウンドにあるかバックグラウンドにあるかは選択肢です(ただし、プロセスは通常バックグラウンドで実行されます)。ご了承ください Nohup.outは、標準出力をリダイレクトしない場合の出力です。

プロセスをバックグラウンドで実行しているときに、親プロセスが停止すると、2つの状況のいずれかが発生します。親が 制御端末 の場合、SIGHUPが子に送信されます。そうでない場合、プロセスは「孤立」している可能性があり、initプロセスによって継承されます。

入力/出力/エラーをリダイレクトするときは、すべてのプロセスが持つファイル記述子を、そのプロセスが親から継承するファイルとは異なるファイルに接続するだけです。これはプロセスの所有権やツリーの深さには影響しません(ただし、バックグラウンドプロセスの場合は、3つすべてをターミナルからリダイレクトすることは常に意味があります)。

以上のことから、プロセス管理に関連する特定の問題がない限り、シェル、サブシェル、またはサブプロセスによるプロセスの作成について心配する必要はないと思います。

6
jwm