
我有一個 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