Bash:ターミナルがサードパーティアプリによって開かれているかどうかを確認する方法


9

私のbashスクリプト(具体的にはmy ~/.bashrc)がターミナルを直接開いた場合にのみ何かを実行し、VS Codeなどのアプリを介してターミナルを開いた場合に何かを実行したいです。どうすればケースを判断できますか?そのための変数はありますか?前もって感謝します。


1
ある種の方法がありますが、私の最初の応答は、askubuntu.com/a/1042727/295286の 2番目の例に 行くことです。VSを開いてenvコマンドを実行してください。使用できるVS固有の変数があるかどうかを確認します。
Sergiy Kolodyazhnyy

1
何もない場合は、別の方法で試してください。ターミナルエミュレータが変数を設定しているかどうかを確認します。私yakuakeは変数PULSE_PROP_OVERRIDE_application.name=Yakuakeセットを使用していて、自分のマシンにxtermセットXTERM_VERSION=XTerm(322)しています。
デザート

@SergiyKolodyazhnyy環境変数アプローチの答えを書いていただけませんか?
デザート

@dessertできますが、VSがインストールされていません。ラッチできる特定の環境変数がある場合、どちらのOPも応答しませんでした。
Sergiy Kolodyazhnyy

@SergiyKolodyazhnyyどちらでもないが、質問のタイトルにはサードパーティ製アプリとあり、ターミナルエミュレーターと同じように機能すると思います。あるenv >env_term1エミュレーターのようenv >env_term2に、2番目のエミュレーターのように答えがあり、それを使用する方法diff env_term{1,2}は非常に便利です。結局のところ、OPは言う例えば VSコード
デザート

回答:


10

おそらく、シェルの祖先をさかのぼって、それが「あなた」に等しいものから始まったのか、それとも別のプログラムから始まったのかを突き止めることによって、おそらくそれを行うことができます。

シェルのPID(プロセスID)を取得し、そこからPPID(親プロセスID)を取得します。それがどこから来たのかを知らせる何かに到達するまで、上に行き続けます。あなたはあなたのシステムで実験する必要があるかもしれません-少なくとも、私はそれが普遍的であるかどうかわかりません。

たとえば、私のシステムでは、シェルのPIDを取得し、psそれを使用して次のことを示していbashます。

$ echo $$
18852
$ ps --pid 18852
  PID TTY          TIME CMD
18852 pts/1    00:00:00 bash

18852のPPIDを取得します。

$ ps -o ppid= -p 18852
18842

PPID(18842)が何であるかを調べます。

$ ps --pid 18842
  PID TTY          TIME CMD
18842 ?        00:00:02 gnome-terminal

これはgnome-terminal、つまりターミナルエミュレーター/ターミナルウィンドウであることがわかります。他のプログラムによって起動されたシェルがターミナルエミュレータウィンドウで実行されていない場合は、これで十分でしょう。

それが十分でない場合は、別のレベルを上げます。

$ ps -o ppid= -p 18842
 2313
$ ps --pid 2313
  PID TTY          TIME CMD
 2313 ?        00:00:00 init

これgnome-terminalにより、によって開始されたことがわかりinitます。私はあなたのシェルが別のプログラムによって開始されたのではないかと思います。


...または、多分pstree -s $$
スティールドライバー

9
「これは、gnome-terminalがinitによって起動されたことを示しています」initが端末ウィンドウを起動することはほとんどありません。むしろ、gnome-terminalが起動したものはすべて終了し、gnome-terminalはinitに親が変更されました。gnome-terminalをチェックアウトすると、ダブルフォークのようです。したがって、実行されると、最初に自身をforkして元のプロセスを強制終了し、新しいプロセスを続行します。
JoL

@JoLフェアポイント。そのinitプロセスはpid 1ではありませんが、それが何かを変えるかどうかはわかりません。
kasperd

どうもありがとう!VS CodeもEclipseもターミナルをの子として実行していないことを検出できましたgnome-terminal。私はコマンドを実行しましたが、if [ $(pstree -s $$ | grep "gnome-terminal" -c) -gt 0 ]; then ...うまくいきました。
PaperBag

9

Visual Studio Codeに関する限り、統合ターミナルに追加の環境変数を設定する方法があるようです。したがって、この構成を使用するようにVisual Studioを設定します。

"terminal.integrated.env.linux": {
  "visual_studio": "true"
}

そして内で~/.bashrc

if [ -n "$visual_studio" ]; then
    # do something for Visual Studio
else
    # do something else for other types of terminal
fi

一般に、bashプロセスに与えられた環境を信頼できます。たとえば$TERM変数と同様のif..then...else...fiブランチを実行し[ "$TERM" = "xterm" ]ます。ケース・ツー・ケースで、あなたはランニングを通じて、環境の違いを調べることができますenvのようにファイルにその保存、各コンソールでenv > output_console1.txt、かつdiff output_console1.txt output_console2.txtによって示唆されているように、コメントでデザート


$Env:varは、Bashの環境変数の構文ではありません。これはPowershellのもののように見えます。
ディートリッヒエップ2018年

@DietrichEppええ、私はもともとVisual Studioで追加の環境変数を設定する方法を研究していましたが、答えがPowerShellを使用していることを見過ごしていました。それで$foo十分です コーヒーはおそらく十分ではありません。
Sergiy Kolodyazhnyy

env-settingを持たないサードパーティプログラムの一般的なケースでは、プログラムを実行するに、ラッパーでカスタム環境変数を設定できます。私の答えをください。
Peter Cordes

2

特定のサードパーティ製アプリについて話している場合は、環境変数を使用します。ほとんどのプログラムは、新しいプロセスをfork + execすると、環境全体を変更せずに渡します。

したがって、確認できるカスタム環境変数でこのアプリを起動します。たとえば、のようにエイリアスを作成するalias vs=RUNNING_FROM_VSCODE=1 VSCodeか、次のようなラッパースクリプトを作成します。

#!/bin/sh
export RUNNING_FROM_VSCODE=1
exec VSCode "$@"

次に、あなた.bashrcで行うことができます

if (($RUNNING_FROM_VSCODE)); then
   echo "started from inside VSCode"
   # RUNNING_FROM_VSCODE=0  # optional if you only want the immediate child
fi

(( ))式がゼロ以外の整数に評価される場合、bash算術ステートメントはtrueです(これが1上記で使用した理由です)。空の文字列(未設定のenv varの場合)はfalseです。これはbashブール変数に適していますがtrue、従来のPOSIX でも簡単に使用および確認できます

if [ "x$RUNNING_FROM_VSCODE" = "xtrue" ]; then
   echo "started from inside VSCode"
fi

アプリがその子の環境をほとんどクリアしても、$PATH変更されずに渡される場合は、これをラッパーで使用できます。

#!/bin/sh
export PATH="$PATH:/dev/null/RUNNING_FROM_VSCODE"
exec VSCode "$@"

そして、bashのようなパターンマッチでそれをチェックして[[ "${PATH%RUNNING_FROM_VSCODE}" != "$PATH" ]]、PATHからサフィックスを取り除くとそれが変わるかどうかをチェックします。

これは、プログラムが見つからない外部コマンドを探すときに、無害に1つの追加のディレクトリルックアップを実行する必要があります。 /dev/nullはどのシステムのディレクトリでもないので、偽のディレクトリとして使用しても安全ENOTDIRです。PATH検索で以前のPATHエントリで探していたものが見つからない場合は、すぐに結果が得られます。


ラッパースクリプトは通常、賢明なアプローチであるため、+ 1です。唯一のマイナーな欠点は、3つのプログラムがある場合、3つのラッパースクリプトまたは3つの異なる引数をとる1つのラッパースクリプトが必要になる可能性があることです。それにもかかわらず、それはしっかりしたアプローチです。
Sergiy Kolodyazhnyy

1

これが私の2セントです。に追加するだけ.bashrcです。terminalsあなたの好きな端末とexportコマンドで置き換えてください。

run_in_terminal(){
  local parent_command="$(ps --no-headers --pid $PPID -o command | awk '{print $1;}')"
  local parent="$(basename $parent_command)"
  local terminals=( gnome-terminal st xterm ) # list your favorite terminal here
  if [[ ${terminals[*]} =~ ${parent} ]]; then
    # Your commands to run if in terminal
    export MY_VAR_IN_TERMINAL="test"
  fi
}
run_in_terminal

これはgnome-terminalのサーバークライアントモデルでは機能しません。
エモント2013年
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.