Bashスクリプトは、それがどのように実行されたかをどのようにして知ることができますか?


10

私は、エコーを介して確認する小さな変更でかなり複雑なコマンドを実行できるようにするために作成しようとしたBashスクリプトを持っています。

コマンドを実行するために端末を強制的に実行する解決策を見つけましたが、私はそのことに興味がありません。私がやりたいことは、Nautilusでスペースを空けてEnterキーを押すだけ(Run Softwareで実行させる)の場合、「端末から実行してください」という通知が表示されます。

私はコマンドを知っているように、ポップアップを発生させることができますが、ターミナル内で実行されているかどうかをBashスクリプトに通知することはできません。常にそうだと思われます。可能ですか?

回答:


10

条件式のman bash下から:

-t fd  
    True if file descriptor fd is open and refers to a terminal.

fd 1が標準出力であるとするとif [ -t 1 ]; then、うまくいくはずです。高度なシェルスクリプトガイドの主張-tをこのように使用がフェイルオーバーしますssh、そしてテストという(STDINを使用して、stdoutがない)ので、次のようになります。

if [[ -t 0 || -p /dev/stdin ]]

-pファイルが存在し、名前付きパイプであるかどうかをテストします。 ただし、これは私には当てはまりません。-p /dev/stdin通常のターミナルセッションとsshセッションの両方で失敗するのに対し、if [ -t 0 ](または-t 1)はどちらの場合でも機能します(高度なシェルスクリプトガイドのそのセクションの問題に関するGillesのコメントも参照してください)。


主要な問題がスクリプトを呼び出してそのコンテキストに適した方法で動作したい特殊なコンテキストである場合、ラッパーとカスタム変数を使用することにより、これらすべての専門性を回避して、多少の手間を省くことができます。

!#/bin/bash

export SPECIAL_CONTEXT=1
/path/to/real/script.sh

これを呼び出すlive_script.shか、代わりにダブルクリックします。もちろん、コマンドライン引数を使用して同じことを行うこともできますが、GUIファイルブラウザーでポイントアンドクリックを実行するには、ラッパーが必要です。


5
これが正解です。これは、POSIXがシェルがインタラクティブかどうかをシェルが検出する必要があると言っている方法でもあります。
mikeserv 2014年

2
@DanielAmaya-入力をリダイレクトした場合、スクリプトはターミナルで実行されていません。問題は、スクリプトが端末で実行されているかどうかを検出する方法です。
mikeserv 2014年

2
あなたはの使用について確信している||内に[ … ]そのような?使用する場合は問題ありません[[ … ]]が、通常は||を使用してコマンドを分離します。最後のコマンド[ -t 0がない[ため、の呼び出しは正しく]ありません。通常、コマンド-pもありません。端末のテストに同意します。それはおそらくそれを行う方法です。それは私が心配している構文です。
Jonathan Leffler、2014年

1
@JonathanLefflerそうだね。に||必要な最終]引数の前にシェル演算子が表示されるため、構文エラーが発生します[
chepner 2014年

3
Advanced Bash-Scripting Guideのそのセクションにはいくつかのエラーがあります。PS1シェルがインタラクティブかどうかを判断する信頼できるテストではありません。「スクリプトがインタラクティブシェルで実行されているかどうかをテストする必要がある場合」も混乱を招きます。コードをテストする必要があるかどうです。通常、スクリプトはインタラクティブシェルで実行されていません(ただし、ソースが提供されている場合は可能です)。 。以下のためのテストiでは、$-シェルが対話型であるかどうかをテストするために正しい方法です。テスト-t 0または-t 2スクリプトは、対話型であることと異なっているの端末で実行されている場合伝えるための正しい方法です。
Gilles「SO-邪悪なこと

0

シェルのネストのレベルを検出するには、bash $ SHLVL変数を使用します。ダブルクリックで「生」を実行するスクリプトでは1になり、ターミナル内で実行されるスクリプトでは2になります。

#!/bin/bash
if (( SHLVL < 2 )) ; then
    echo "Please run this from a terminal."
    read -p "Press <Enter> to close this window"
    exit 1
fi
# rest of script

0

goldilocksの答えは通常のケースではおそらく正しいですが、エッジケースがあるように見えます。私の場合、私のxserverは起動するように構成されてtty1おり、tty から離れることはありません。Xorg stdoutがTTY の場合、クライアントはデフォルトでそのTTYをファイル記述子にリンクしているようです。

これが私が私の問題を解決した方法です:

#!/bin/bash
isxclient=$( readlink /dev/fd/2 | grep -q 'tty' && [[ -n $DISPLAY ]] ; echo $? )
if [[ ! -t 2  || $isxclient == "0" ]]; then
        notify-send "Script wasn't started from an interactive shell"
else
        echo "Script was started from an interactive shell"
fi

これをテストして、それがより標準的なX構成で機能するかどうかを確認していません。また、これが唯一のエッジケースであることを疑っています。より一般的に適用可能な解決策を見つけた場合は、戻って私たちに教えてください。


-2

もう1つは、bashオプションを使用して内部変数を設定することです$-

から.bashrc

# If not running interactively, don't do anything
case $- in
    *i*) ;;
    *) return;;
esac

対話型シェルは必ずしも端末に接続されている必要はありません。その接続で開始されたものは自動的にインタラクティブに開始されますが、これも可能ですcmd | sh -i | cmd
mikeserv 2014年

このコードはスクリプトで実行されています。端末で実行している場合でも、インタラクティブにはなりません。
Gilles「SO-邪悪なことをやめなさい」2014
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.