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

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

私は、echo と read を通じて尋ねられる小さな変更を加えた、かなり複雑なコマンドを実行するのに役立つ Bash スクリプトを作成しようとしていました。

コマンドを実行するためにターミナルを強制的に実行する解決策を見つけましたが、私はそれに興味はありません。私がやりたいのは、Nautilus で何も考えずに Enter キーを押すと (Run Software で実行する)、「ターミナルから実行してください」という通知が静かにポップアップ表示されることです。

コマンドを知っているので、ポップアップを表示させることはできますが、Bash スクリプトに、ターミナル内で実行されているかどうかを判断させることができません。常にそう判断しているようです。そんなことは可能なのでしょうか?

答え1

man bash下から条件式:

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

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

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 ファイル ブラウザーでポイント アンド クリックを機能させるには、ラッパーが必要になります。

答え2

シェルのネスト レベルを検出するには、bash $SHLVL 変数を使用します。ダブルクリックして 'raw' を実行するスクリプトでは 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

注意: (()) 内の数値変数をテストする場合、$ は必要ありません。

答え3

典型的なケースでは goldilocks の回答が正しいと思われますが、特殊なケースもあるようです。私の場合、xserver は起動時にtty1その tty から切り離されることはありません。Xorg がstdoutTTY である場合、クライアントはデフォルトでその 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 構成で動作するかどうかはテストしていませんし、これが唯一の例外的なケースであるかどうかも非常に疑問です。より一般的に適用可能な解決策を見つけた方は、ぜひまたご連絡ください。

答え4

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

から.bashrc

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

関連情報