Bash 腳本如何知道它是如何運作的?

Bash 腳本如何知道它是如何運作的?

我有一個 Bash 腳本,我試圖製作它來幫助我運行一個相當複雜的命令,並進行一些小的更改,它會透過 echo 和 read 詢問我有關的資訊。

我已經找到了強制它運行終端來執行命令的解決方案,但我對此不感興趣。我希望它做的是,如果我在 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應該適合您。這進階 Shell 腳本編寫指南使用這種方式的聲明-t將進行故障轉移ssh,因此測試(使用標準輸入,而不是標準輸出)應該是:

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

-p測試文件是否存在並且是命名管道。 然而,我注意到,根據經驗,這對我來說是不正確的:-p /dev/stdin普通終端和 ssh 會話都失敗,而if [ -t 0 ](或-t 1) 在這兩種情況下都有效(另請參閱下面關於該部分中問題的Gilles評論進階 Shell 腳本編寫指南)。


如果主要問題是一個專門的上下文,您希望從中調用腳本以適合該上下文的方式運行,那麼您可以迴避所有這些技術細節,並通過使用包裝器和自定義變量來省去一些麻煩:

!#/bin/bash

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

呼叫這個live_script.sh或其他名稱,然後雙擊它。當然,您可以使用命令列參數完成相同的事情,但是仍然需要一個包裝器來使 GUI 文件瀏覽器中的指向和單擊工作正常。

答案2

使用 bash $SLVL 變數來偵測 shell 嵌套的層級。在透過雙擊執行「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

儘管金髮女孩的答案在典型情況下可能是正確的,但似乎確實存在邊緣情況。就我自己而言,我的 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

相關內容