Bashスクリプトはどのように実行するのか知っていますか?

Bashスクリプトはどのように実行するのか知っていますか?

いくつかの変更を含むかなり複雑なコマンドを実行するのに役立つようにする Bash スクリプトがあります。

コマンドを実行するために端末を強制的に実行するソリューションを見つけましたが、それには興味がありません。私が望むのは、Nautilusにスペースを作成してEnterキーを押すと(実行中のソフトウェアで実行されるように)、「ターミナルでこのプログラムを実行してください」という通知がスムーズにポップアップされることです。

コマンドを知っているようにポップアップを発生させることができますが、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テスト(標準出力ではなく標準入力を使用)は次のようにする必要があります。

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 $SLVL変数を使用して、シェルの入れ子レベルを検出します。ダブルクリックして「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はそのttyから始まり、tty1決してそのttyから離れないように設定されています。 Xorgstdoutが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構成で動作するかどうかをテストしていませんが、それが唯一の極端なケースかどうか疑問に思います。もっと一般的に適用できる解決策を見つけた人がいる場合は、もう一度お知らせください。

答え4

別の方法は、bashオプションを使用して内部変数を設定することです$-

から.bashrc

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

関連情報