質問を正確に表現するのは難しいと思いますが、最善を尽くします。私はdwm
をデフォルトのウィンドウマネージャーとして使用し、dmenu
をアプリケーションランチャーとして使用しています。ブラウザ以外のGUIアプリケーションはほとんど使用していません。私の作業のほとんどは、コマンドラインから直接行われます。さらに、私はオペレーティングシステム、アプリケーションなどに関するミニマリズムの大ファンです。私が取り除くことができなかったツールの1つは、アプリケーションランチャーでした。主な理由は、アプリケーションランチャーがどのように動作するか/何をするかについての正確な理解がないためです。広範なインターネット検索でさえ、あいまいな説明しか表示されません。私がしたいのは、実際にアプリケーションを起動する以外はまったく使用しないため、アプリケーションランチャーも削除することです。これを行うために、シェルからアプリケーションを「正しく」起動する方法を本当に知りたいのです。これにより、「正しく」の意味は、「アプリケーションランチャーのように」と概算できます。十分に理解していないため、すべてのアプリケーションランチャーが同じように動作するとは主張していません。
シェルからプロセスを起動する次の方法について知っています。
exec /path/to/Program
新しいプロセスを作成せずに、指定したコマンドでシェルを置き換えますsh -c /path/to/Program
起動シェル依存プロセス/path/to/Program
起動シェル依存プロセス/path/to/Program 2>&1 &
シェルに依存しないプロセスを起動するNohup /path/to/Program &
シェルに依存しないプロセスを起動し、出力をNohup.out
にリダイレクトします更新1:例を示します。 dmenu
は、さまざまな条件下でps -efl
を繰り返し呼び出して再構築します。新しいシェル/bin/bash
を生成し、このシェルの子としてアプリケーション/path/to/Program
を生成します。子供がそこにいる限り、シェルは周りにいます。 (これをどのように管理するかは私を超えています...)対照的に、シェルからNohup /path/to/Program &
を発行すると/bin/bash
になると、プログラムはこのシェルの子になりますが、このシェルを終了すると、プログラムの親は最上位のプロセスです。つまり、最初のプロセスが/sbin/init verbose
とPPID 1
がある場合は、プログラムの親になります。グラフを使用して説明しようとしたものは次のとおりです。chromium
はdmenu
を介して起動され、firefox
はexec 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
のプロセスである必要がありますか?
まあ、あなたはそれをかなりよく理解しているようです。あなたが持っているもののいくつかを明確にするために、
_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つのシェルスクリプト(それぞれdmenu
、dmenu_path
、dmenu_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 "$@") &
G-Manの答えがとても好きです。しかし、私はあなたが懸念を混乱させていると思うので対応します。ウェインが指摘するように、最良の答えは「あなたが望む結果を得るものは何でも」です。
Unixプロセス管理では、すべてのプロセスに親があります。これの1つの例外は、ブート時にOSによって開始されるinit
プロセスです。親プロセスが停止したときに、親プロセスがすべての子プロセスをそれと一緒に取るのは正常な動作です。これは、SIGHUPシグナルをすべての子プロセスに送信することによって行われます。 SIGHUPのデフォルト処理はプロセスを終了します。
ユーザープロセスのシェル生成は、選択した言語で fork(2) / exec(3) 呼び出しをコーディングした場合と同じです。シェルは親であり、シェルが終了した場合(たとえば、ユーザーがログオフした場合)、シェルが生成する子プロセスはそれに伴って進みます。あなたが説明するニュアンスは、その振る舞いを修正するための単なる方法です。
exec /path/to/program
は exec(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つすべてをターミナルからリダイレクトすることは常に意味があります)。
以上のことから、プロセス管理に関連する特定の問題がない限り、シェル、サブシェル、またはサブプロセスによるプロセスの作成について心配する必要はないと思います。