スクリプトから最も近い対話型祖先シェルの名前をどのように取得できますか?

スクリプトから最も近い対話型祖先シェルの名前をどのように取得できますか?

$-インクルードを使用できることを知っています$PS1シェルがインタラクティブであるかどうかを判断するために、ヌルをチェックまたはチェックします。

しかし、これらのソリューションは現在シェルでのみ機能します。

インタラクティブな直接親シェルを見つけるためのbashスクリプトがあります。

たとえば、

  1. 対話型シェル:zsh
  2. bashスクリプト1 bashスクリプト2の実行
  3. bashスクリプト2には、リアルタイムの対話型シェルを見つけるメカニズムが含まれています。

したがって、対話型シェルでbashスクリプト1を実行すると、zsh出力はzsh

スクリプトがサブシェルで実行されたときにこれを行う方法がわかりません。

ノート

スクリプトを実行するのではなく、実行したいです。

言う

最初の対話型祖先シェルを見つけるためのbashスクリプトがあります。

最初の祖先とは、ボトムアッププロセスチェーンスキャン中に出会った最初の対話型シェルを意味します。

たとえば、次の場合:zsh(最初の対話型シェル) - > bash(2番目の対話型シェル) - > bash(スクリプト1のバッチシェル) - > bash(スクリプト2のバッチシェル)、私たちはbash (2番目の対話型シェル)を出力しようとしています。シェル)。

答え1

これは非常に奇妙な要求です。どのインタラクティブシェルがスクリプトを呼び出すのか、またはインタラクティブシェル以外のプログラムを呼び出してスクリプトを呼び出すのかを気にする必要があるのはなぜですか?これは匂いがとても強いです。XYの問題

必ず知っておく必要がある場合は、調べようとすることができますが、完全に信頼できる方法はなく、一般的な状況で動作する方法は1つしかないようです。

最初から始めて、探しているプロセスが見つかるまで、または行き過ぎたことを示すプロセスが見つかるまで、スクリプト$PPIDの祖先プロセス()を追跡します。ps -o ppid= -p $ancestor_pid

簡単な戦略は、さまざまなプロセスグループ()でプロセスを見つけることですps -o pgid= -p $ancestor_pid。通常の状況でスクリプトが対話型シェル(呼び出し側スクリプト)によって呼び出される場合、到達するプロセスはスクリプト(スクリプトの親)を実行するジョブ制御機能を持つシェルです。

この戦略が間違っている可能性があるいくつかの例は次のとおりです。

  • チェーンのプロセスの1つが終了しました。
  • スクリプトはインタラクティブシェルでは呼び出されず、クローン操作、X11プログラムなどを介して呼び出されます。

lsofプロセスの標準入力、標準出力、および標準エラー(たとえば、Linuxの外部への移植性が必要ない場合は使用または経由)がスクリプトと同じ端末であることを確認したい場合や望ましくない場合があります。/proc次の状況をどのように処理するかによって異なります。

bash$ xterm -e your_script

答え2

オプションを確認してください。

[ "$-" = "${-#*i}" ] ||
echo shell is interactive

ファイル記述子を確認することもできます。これは少し違います。シェル自体がインタラクティブであるかどうかは必ずしもわかりませんが、端末と通信しているかどうかはわかります。

for fd in 0 1 2
do     [ -t "$fd" ] && 
       break 
done|| echo shell fds 0 1 2 are not connected to a terminal.

私たちは少しハッキングすることで、端末のすべての用途を把握しようとすることができます。

tty_users()
    for fd in 0 1 2 "$@"
    do     [ -t "$fd" ] && {
           fuser "$(tty)"
           break; } <&"$fd"
    done 

現在シェルで実行され、最初に検出された端末で実行されているプロセスのプロセスIDのリストを印刷します。std(in|out|err) (既定値 - 異なる引数をテストするには、関数の数値引数を渡します.)それぞれ。シェル変数を$fdこの端末に関連付けられたファイル記述子番号に設定するか、標準記述子がない場合、または端末に関連付けられた引数がない場合はfalseを返します。

上記は、端末のセッションID(存在する場合)が見つからない限り、取得できる最も近い情報です。

ps -osid= -p"$$"

これにより、制御端末の所有者のpidが返されます(存在する場合)。

展示する:

echo "$$"; sh -c 'sh -c "ps -osid= -p\"\$$\""' 

6023
6023

しかし、これらのことにのみ頼ることはできません。まったくそうではありません。望むより:

sh -acm 'IFS=\; i=0;eval "$0"'          \
        '[ "$i" -lt 5 ] && eval "$*"'   \
        'ps -opid -opgid -p"$$"'        \
        'sh -acm "$0" "$0" "$@" i=$((i+=1))'
  PID  PGID
28766 28766
  PID  PGID
28768 28768
  PID  PGID
28770 28770
  PID  PGID
28772 28772
  PID  PGID
28774 28774

願いより?私がこれらのプロセスを実行している対話型シェルはそのリストにもありません。各shサブプロセスは深さが5に達するまで独自のサブプロセスを開始し、各サブプロセスが深さに達するとpsPIDおよびPGID印刷を呼び出します。すべてプロセスは新しいPGIDを取得します。タスク制御は、端末がタスクをテストするより直接的な方法であることを除いて、端末と同様に対話型シェルに関連しています。

関連情報