如何將 GUI 添加到 Linux Shell 腳本
已發表: 2022-01-29 您可以在 Bash 腳本中使用 GUI 窗口、滑塊、單選按鈕、進度條等。 了解如何使用zenity
工具包,並讓您的 Bash 腳本煥然一新。 我們會告訴你怎麼做。
Bash 腳本是一種功能強大的編程語言,因為它內置在 Bash shell 中,所以每個人都可以輕鬆使用它。 它是一種易於開始編程的語言。因為它是解釋型的,所以您不需要編譯腳本。 一旦您編輯了腳本文件並使其可執行,您就可以運行它。 這使得編碼、運行和調試週期非常高效。
人們對 Bash 腳本有兩個主要抱怨,首先是速度。 因為 Bash shell 解釋腳本中的命令,所以它們的執行速度不如編譯的代碼。 然而,這就像抱怨拖拉機不如汽車快; 它們適用於不同的事物。
不過,有兩種速度。 您通常可以拼湊一個快速腳本並使用它來執行任務,這比使用編譯語言(例如 C)開發解決方案要快得多。
人們對 Bash 腳本的第二個抱怨是用戶界面——它是一個終端窗口。 當然,有時界面並不重要。 如果唯一會使用腳本的人是它的作者,那麼界面可能就沒有那麼重要了。 對於執行後台和批處理類型處理的腳本也無關緊要。 通常,此類腳本不需要太多(如果有的話)用戶交互。
有時您確實需要比終端窗口更直觀和現代的東西。 大多數人都熟悉圖形用戶界面 (GUI)。 要為人們提供盡可能順暢的體驗,您必須從腳本中創建和使用 GUI 元素。
zenity 應用程序
zenity
允許您在 Bash 腳本中加入各種圖形界面元素。 這是一個功能強大的工具包,可為您的腳本提供現代感和現代、熟悉的外觀。
zenity
預裝在 Ubuntu、Fedora 和 Manjaro 發行版上。 它是 GNOME 的一部分。 如果您使用 KDE,您可能想要查看kdialog
,儘管zenity
確實可以在任何桌面環境中運行。
本文中的示例向您展示瞭如何從命令行創建不同的對話框窗口,如何在變量中捕獲它們的返回值和用戶選擇,以及如何在腳本中使用對話框窗口。
我們完成了一個使用所有三種類型的對話窗口的小應用程序。
日曆對話框窗口
日曆對話窗口允許某人選擇日期。 要創建一個zenity
需要兩個單詞的單個命令:
zenity--日曆
出現日曆對話窗口。 它具有標準日期選擇器所期望的所有功能。 您可以更改月份和年份,然後單擊某一天以選擇該日期。 默認情況下,當窗口出現時,今天的日期會突出顯示。
單擊“確定”關閉對話窗口並選擇突出顯示的日期。 雙擊一個日期做同樣的事情。
如果您不想選擇日期,請單擊“取消”,按鍵盤上的“Esc”鍵,或關閉對話窗口。
在上面的示例中,選擇了 2019 年 8 月 19 日。 如果用戶單擊“確定”,則日曆將關閉,所選日期將打印在終端窗口中。
你可以忽略這一行,“GTKDialog mapped without a transient parent。 這是不鼓勵的。”
GTK 代表 GIMP Tool Kit,它是用於開發 GNOME 界面的工具包。 它最初是由 GNU Image Manipulation Program (GIMP) 的作者設計的。 GNU 代表 GNU's Not Unix。
GTK 引擎警告zenity
的作者,他們以非標準方式使用了 GTK 組件。
捕獲日期值
將日期打印到終端對我們來說並沒有多大作用。 如果我們要從我們的腳本之一調用這個日曆,我們需要捕獲選定的日期值,以便我們可以在我們的腳本中使用它做一些有用的事情。 我們還將稍微定制日曆。
我們將在日曆中使用以下選項。 它們都必須與雙破折號“–”標誌一起使用:
- –text :指定要在日曆中顯示的文本字符串。 它取代了默認的“從下面選擇一個日期”。
- –title :設置日曆對話窗口的標題。
- –day :設置日曆打開時選擇的日期。
- –month :設置日曆打開時選擇的月份。
- –year :設置日曆打開時選擇的年份。
我們使用一個名為ChosenDate
的變量來捕獲從日曆返回的日期。 我們正在使用echo $ChosenDate
將該日期打印到終端窗口。
是的,我們在前面的示例中獲得了相同的結果,但是在這裡,我們將選定的日期存儲在一個變量中。 在前面的示例中,它被打印並忘記了。
ChosenDate=$(zenity -- calendar --text "Choose a date" --title "How-To Geek Rota" --day 1 --month 9 --year 2019); 迴聲 $ChosenDate
現在,日曆顯示我們的提示和我們的窗口標題。 日期設置為我們選擇的開始日期,而不是今天的日期。
我們還可以自定義選擇時返回的日期字符串的格式。 --date-format
選項必須後跟格式說明符。 這是一串標記,用於定義要包含在輸出中的數據和格式。 這些標記與用於strftime()
C 語言函數的標記相同,並且有大量的選擇。
我們使用的令牌是:
- %A :星期幾的全名。
- %d :以數字表示的月份中的日期。
- %m :以數字表示的月份。
- %y :年份為兩位數(無世紀)。
ChosenDate=$(zenity -- calendar --text "選擇一個日期" --title "How-To Geek Rota" --date-format="%A %d/%m/%y" --day 1 --第 9 個月——2019 年); 迴聲 $ChosenDate
有人選擇日期:
並且使用我們的格式返回日期。 它顯示星期幾的名稱,後跟按歐洲順序排列的日期:日、月、年。
文件選擇對話框窗口:選擇文件
文件選擇對話框窗口相當複雜。 人們可以瀏覽文件系統,突出顯示一個或多個文件,然後單擊“確定”以選擇這些文件或完全取消選擇。
zenity
提供了所有這些功能,甚至更多。 它與日曆對話窗口一樣易於使用。
我們將使用的新選項是:
- –file-selection :告訴
zenity
我們要使用文件選擇對話框窗口。 - –multiple :允許某人選擇多個文件。
- –file-filter :告訴文件對話框窗口要顯示哪些文件類型。
zenity --file-selection --tile "How-To Geek" --multiple --file-filter='*.mm *.png *.page *.sh *.txt'
文件選擇對話框窗口的功能與任何其他文件選擇窗口一樣。
用戶可以瀏覽文件系統並選擇她選擇的文件。
我們已經瀏覽到一個新目錄並選擇了一個名為“button_hybrid.png”的文件。
單擊“確定”時,文件選擇對話窗口關閉,文件名和路徑打印在終端窗口中。
如果您需要在任何進一步的處理中使用文件名,您可以在變量中捕獲它,就像您對日曆中的日期所做的那樣。
文件選擇對話框窗口:保存文件
如果我們添加一個選項,我們可以將文件選擇對話框窗口變成文件保存對話框窗口。 選項是--save
。 我們還將使用--confirm-overwrite
選項。 這會提示該人確認他想要覆蓋現有文件。
響應=$(zenity --file-selection --save --confirm-overwrite); 迴聲$響應
出現文件保存對話框窗口。 請注意,有人可以在其中鍵入文件名的文本字段。
用戶可以瀏覽到他在文件系統中選擇的位置,為文件提供名稱,或單擊現有文件以覆蓋它。
在上面的示例中,用戶突出顯示了現有文件。
當他單擊“確定”時,會出現一個確認對話框窗口,要求他確認是否要替換現有文件。 請注意文件名出現在警告對話框中。 正是這種對細節的關注賦予了zenity
專業的外觀。
如果我們沒有使用--confirm-overwrite
選項,該文件將被靜默覆蓋。
文件的名稱存儲在變量Response
中,該變量會打印到終端窗口。
通知對話框窗口
使用zenity
,在您的腳本中包含光滑的通知對話框窗口是毫不費力的。 您可以調用一些常用的對話窗口來為用戶提供信息、警告、錯誤消息和問題。
要創建錯誤消息對話框窗口,請使用以下命令:
zenity --error --width 300 --text "權限被拒絕。無法寫入文件。"
我們使用的新選項是:
- –error :告訴
zenity
我們要使用錯誤對話框窗口。 - –width :設置窗口的初始寬度。
錯誤對話框窗口以指定的寬度出現。 它使用標準的 GTK 錯誤圖標。
要創建信息對話窗口,請使用以下命令:
zenity --info --width 300 --text "更新完成。點擊確定繼續。"
我們使用的新選項是--info
,它告訴zenity
創建一個信息對話窗口。
要創建問題對話窗口,請使用以下命令:
zenity --question --width 300 --text "你樂意繼續嗎?"; 迴聲$?
我們使用的新選項是--question
,它告訴zenity
創建一個問題對話窗口。
$?
是一個特殊的參數。 它保存最近執行的前台管道的返回值。 一般而言,這是來自最近關閉的流程的值。 零值表示“OK”,一個或多個值表示“取消”。
這是一種通用技術,您可以將其應用於任何zenity
對話窗口。 通過在您的腳本中檢查該值,您可以確定從對話窗口返回的數據是否應該被處理或忽略。
我們單擊“是”,因此返回代碼為零,表示“確定”。
要創建警告對話框窗口,請使用以下命令:
zenity --warning --title "硬盤空間不足" --width 300 --text "可能沒有足夠的硬盤空間來保存備份。"
我們使用的新選項是--warning
,它告訴zenity
創建一個警告對話框窗口。
出現警告對話框窗口。 這不是一個問題,所以它只有一個按鈕。
進度對話框窗口
您可以使用zenity
進度對話框窗口來顯示一個進度條,指示您的腳本距離完成有多近。
進度條根據從您的腳本中輸入的值進行推進。 為了演示原理,請使用以下命令:
(for i in $(seq 0 10 100); do echo $i; sleep 1; done)
該命令分解如下:
-
seq
命令以 10 為步長遍歷從 0 到 100 的序列。 - 在每一步,值都存儲在變量
i
中。 這將打印到終端窗口。 - 由於
sleep 1
命令,該命令暫停一秒鐘。
我們可以將它與zenity
進度對話框窗口一起使用來演示進度條。 請注意,我們將上一個命令的輸出通過管道傳輸到zenity:
(for i in $(seq 0 10 100); do echo $i; sleep 1; done) | zenity --progress --title "How-To Geek" -- 自動關閉
我們使用的新選項是:
- –progress :告訴
zenity
我們要使用進度對話框窗口。 - –auto-close :當進度條達到 100% 時關閉對話框。
出現進度對話框窗口,進度條向 100% 前進,在每一步之間暫停一秒鐘。
我們可以使用管道值到zenity
的概念來在腳本中包含進度對話框窗口。
在編輯器中輸入此文本並將其保存為“progress.sh”。
!/bin/bash 功能工作清單(){ echo "# 第一個工作項" 迴聲“25” 睡覺 1 echo "# 第二個工作項" 迴聲“50” 睡覺 1 echo "# 第三個工作項" 迴聲“75” 睡覺 1 echo "# 最後一個工作項" 迴聲“100” 睡覺 1 } 工作清單 | zenity --progress --title "How-To Geek" --auto-close 出口 0
以下是腳本的細分:
- 該腳本定義了一個名為
work-list
的函數。 這是您放置命令和指令以執行實際工作的地方。 將每個sleep 1
命令替換為您的真實命令。 -
zenity
接受echo "# ..."
行並在進度對話框窗口中顯示它們。 更改這些行的文本,以便它們將信息性消息傳遞給用戶。 - 包含數字的
echo
顯行,例如echo "25"
,也被zenity
接受並設置進度條的值。 - 工作列表函數被調用並通過管道傳輸到
zenity
。
使用此命令使腳本可執行:
chmod +x 進度.sh
使用此命令運行腳本:
./progress.sh
腳本運行,並且文本消息隨著腳本的每個階段的執行而變化。 進度條逐步向 100% 移動。
比例對話框窗口
比例對話框窗口允許用戶移動滑塊來選擇數值。 這意味著她不能輸入太高或太低的值。
我們使用的新選項是:
- –scale :告訴
zenity
我們要使用比例對話框窗口。 - –min-value :設置刻度的最小值。
- –max-value :設置刻度的最大值。
- –step :設置使用箭頭鍵時滑塊移動的量。 如果有人使用鼠標,這不會影響滑塊的移動。
- –value :設置滑塊的初始值和位置。
這是我們正在使用的命令:
Response=$(zenity --scale --title "How-To Geek" --text "選擇放大倍率。" --min-value=0 --max-value=30 --step=3 --value15); 迴聲$響應
滑塊對話窗口出現,滑塊設置為 15。
用戶可以移動滑塊來選擇一個新值。
當她單擊“確定”時,該值將傳輸到變量Response
並打印到終端窗口。
條目對話窗口
輸入對話窗口允許某人輸入文本。
我們使用的新選項是:
- –entry :告訴
zenity
我們要使用一個條目對話窗口。 - –entry-text :如果您想在文本輸入字段中輸入建議值,可以使用它。 我們使用“”來強制一個空字段。 這不是嚴格要求的,但我們想記錄該選項。
完整的命令如下所示:
Response=$(zenity --entry --text "輸入你的搜索詞" --title "Howe-To Geek" --entry-text=""); 迴聲$響應
將出現一個簡單的對話窗口,其中包含一個文本輸入字段。
有人可以鍵入和編輯文本。
當他單擊“確定”時,他鍵入的值將分配給變量 Response。 我們使用 echo 在終端窗口中打印變量的值。
把它們放在一起
讓我們將這些技術放在一起並創建一個功能性腳本。 該腳本將執行硬件信息掃描並在滾動文本窗口中將結果呈現給用戶。 她可以選擇長或短掃描類型。
對於這個腳本,我們將使用三種類型的對話窗口,其中兩種對我們來說是新的:
- 第一個是列表對話窗口。 它允許某人做出選擇。
- 第二個是進度對話框窗口,讓用戶知道正在發生的事情,她應該等待。
- 第三個是文本信息窗口,向用戶顯示結果。
在編輯器中輸入此文本並將其保存為“hardware-info.sh”。
#!/bin/bash # 顯示此計算機的硬件列表 臨時文件=$(mktemp) ListType=`zenity --width=400 --height=275 --list --radiolist \ --title '硬件掃描' \ --text '選擇掃描類型:' \ --列'選擇'\ --column '掃描類型' TRUE "Short" FALSE "Long"` 如果 [[ $? -eq 1]]; 然後 # 他們按下了取消或關閉了對話窗口 zenity --error --title="掃描被拒絕" --width=200 \ --text="跳過硬件掃描" 1號出口 elif [ $ListType == "短" ]; 然後 # 他們選擇了短單選按鈕 標誌="--短" 別的 # 他們選擇了長單選按鈕 標誌="" 菲 # 在 $Flag 中搜索具有適當值的硬件信息 hwinfo $標誌 | 三通 >(zenity --width=200 --height=100 \ --title="整理信息" --progress \ --pulsate --text="正在檢查硬件..." \ --auto-kill --auto-close) >${TempFile} # 在滾動窗口中顯示硬件信息 zenity --width=800 --height=600 \ --title "硬件詳細信息" \ --text-info --filename="${TempFile}" 出口 0
使用此命令使其可執行:
chmod +x 硬件信息.sh
此腳本創建一個臨時文件,文件名保存在 TempFile 變量中:
臨時文件=$(mktemp)
該腳本使用--list
選項創建一個稱為列表對話窗口的zenity
對話窗口。 行尾的“\”字符告訴腳本將它們視為一個環繞的長行。 這是過程:
- 我們指定窗口的寬度和高度。
- 列表對話框窗口支持列。
--radiolist
選項使第一列成為單選按鈕列。 - 我們為窗口設置了標題和文本提示。
- 我們將第一列的標題設置為“選擇”。 此列的內容將是單選按鈕。
- 我們將第二列的標題設置為“選擇”,並提供第二列的內容。 此列包含兩個文本標籤:“短”和“長”。 TRUE 和 FALSE 指示符表示對話框窗口出現時默認選擇“Short”選項。
- 我們將此對話窗口的結果存儲在一個名為
ListType
的變量中。
ListType=`zenity --width=400 --height=275 --list --radiolist \ --title '硬件掃描' \ --text '選擇掃描類型:' \ --列'選擇'\ --column '掃描類型' TRUE "Short" FALSE "Long"`
如果用戶按下“取消”,我們不需要檢查ListType,
我們可以簡單地退出。 如果他按下“OK”,我們需要確定他是否選擇了“Short”或“Long”單選按鈕:
- 特殊參數
$?
如果用戶按下“確定”,則為零。 如果他按下“取消”或關閉窗口,則等於 1。 - 如果它等於 1,則腳本顯示錯誤信息對話框窗口並退出。 如果他按下“OK”,我們繼續測試
ListType
變量中的值。 - 如果
ListType
變量包含值“Short”,則腳本將名為Flag
的變量設置為等於“–short”。 - 如果
ListType
變量不包含值“Short”,則它必須包含值“Long”。 該腳本將一個名為Flag
的變量設置為等於“”,這是一個空字符串。 - 該腳本將在下一節中使用
Flag
變量。
如果 [[ $? -eq 1]]; 然後 # 他們按下了取消或關閉了對話窗口 zenity --error --title="掃描被拒絕" --width=200 \ --text="硬件掃描被跳過" 1號出口 elif [ $ListType == "短" ]; 然後 # 他們選擇了短單選按鈕 標誌="--短" 別的 # 他們選擇了長單選按鈕 標誌="" 菲
現在腳本知道用戶想要哪種類型的掃描,我們可以執行硬件信息掃描:
- 該腳本調用
hwinfo
命令並將Flag
變量中的值傳遞給它。 - 如果
Flag
包含“–short”,則hwinfo
命令執行短掃描。 如果Flag
的值為“”,則不會向hwinfo
傳遞任何內容,並且會執行默認的長掃描。 - 該腳本將
hwinfo
的輸出通過管道傳輸到tee
。tee
將輸出發送到zenity
和TempFile
。 - 該腳本創建一個進度條對話窗口。 它設置對話窗口的寬度和高度,以及標題和提示文本。
- 該腳本無法預先知道
hwinfo
命令將產生多少信息,因此它無法將進度條正確設置為 100%。--pulsate
選項使進度對話框顯示移動指示器。 這會通知用戶正在發生某些事情,他應該等待。 - 如果有人單擊“取消”,
--auto-kill
選項將終止腳本。 -
--auto-close
選項會導致進度對話框在其監控的進程完成時自動關閉。
# 在 $Flag 中搜索具有適當值的硬件信息 hwinfo $標誌 | 三通 >(zenity --width=200 --height=100 \ --title="整理信息" --progress \ --pulsate --text="正在檢查硬件..." \ --auto-kill --auto-close) >${TempFile}
當hwinfo
掃描完成時,腳本調用zenity
來創建一個帶有--text-info
選項的文本信息對話窗口。 文本信息對話框窗口顯示TempFile
文件的內容:
- 該腳本設置對話窗口的寬度和高度以及標題文本。
-
--flename
選項用於讀取保存在TempFIle
變量中的文件的內容。
# 在滾動窗口中顯示硬件信息 zenity --width=800 --height=600 \ --title "硬件詳細信息" \ --text-info --filename="${TempFile}"
當用戶關閉文本信息對話窗口時,腳本退出。
出口 0
讓我們把它燒起來看看。
./硬件信息.sh
出現列錶框。 默認選擇“短”選項。
讓我們選擇“Long”,然後單擊“OK”。
進度窗口出現,帶有一個滑動指示器。 它會一直保留在屏幕上,直到硬件掃描完成。
硬件掃描完成後,將出現文本信息對話框窗口,其中包含掃描的詳細信息。
點擊“確定”。
即使是頑固的命令行專家也不得不承認,幾個 GUI 對話框窗口可以給不起眼的 Bash 腳本帶來專業的感覺。