如何將 GUI 添加到 Linux Shell 腳本

已發表: 2022-01-29

從 Ubuntu 終端啟動的 zenity 信息窗口。

您可以在 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--日曆
廣告

出現日曆對話窗口。 它具有標準日期選擇器所期望的所有功能。 您可以更改月份和年份,然後單擊某一天以選擇該日期。 默認情況下,當窗口出現時,今天的日期會突出顯示。

2019 年 7 月的 Zenity 日曆窗口。

單擊“確定”關閉對話窗口並選擇突出顯示的日期。 雙擊一個日期做同樣的事情。

如果您不想選擇日期,請單擊“取消”,按鍵盤上的“Esc”鍵,或關閉對話窗口。

選擇了 2019 年 8 月 19 日的 Zenity 日曆窗口。

在上面的示例中,選擇了 2019 年 8 月 19 日。 如果用戶單擊“確定”,則日曆將關閉,所選日期將打印在終端窗口中。

在終端窗口中顯示的日曆 (08/19/2019) 上選擇的日期。

你可以忽略這一行,“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 

現在,日曆顯示我們的提示和我們的窗口標題。 日期設置為我們選擇的開始日期,而不是今天的日期。

選擇了開始日期(2019 年 9 月 1 日)的 zenity 日曆。

廣告

我們還可以自定義選擇時返回的日期字符串的格式。 --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 

有人選擇日期:

選擇了 2019 年 9 月 16 日的 zenity 日曆窗口。

並且使用我們的格式返回日期。 它顯示星期幾的名稱,後跟按歐洲順序排列的日期:日、月、年。

文件選擇對話框窗口:選擇文件

文件選擇對話框窗口相當複雜。 人們可以瀏覽文件系統,突出顯示一個或多個文件,然後單擊“確定”以選擇這些文件或完全取消選擇。

zenity提供了所有這些功能,甚至更多。 它與日曆對話窗口一樣易於使用。

我們將使用的新選項是:

  • –file-selection告訴zenity我們要使用文件選擇對話框窗口。
  • –multiple允許某人選擇多個文件。
  • –file-filter告訴文件對話框窗口要顯示哪些文件類型。
 zenity --file-selection --tile "How-To Geek" --multiple --file-filter='*.mm *.png *.page *.sh *.txt' 

文件選擇對話框窗口的功能與任何其他文件選擇窗口一樣。

zenity 文件部分對話框窗口,其中選擇了一個文件夾。

用戶可以瀏覽文件系統並選擇她選擇的文件。

zenity 文件選擇對話框窗口,其中選擇了一個文件

廣告

我們已經瀏覽到一個新目錄並選擇了一個名為“button_hybrid.png”的文件。

單擊“確定”時,文件選擇對話窗口關閉,文件名和路徑打印在終端窗口中。

如果您需要在任何進一步的處理中使用文件名,您可以在變量中捕獲它,就像您對日曆中的日期所做的那樣。

文件選擇對話框窗口:保存文件

如果我們添加一個選項,我們可以將文件選擇對話框窗口變成文件保存對話框窗口。 選項是--save 。 我們還將使用--confirm-overwrite選項。 這會提示該人確認他想要覆蓋現有文件。

 響應=$(zenity --file-selection --save --confirm-overwrite); 迴聲$響應

出現文件保存對話框窗口。 請注意,有人可以在其中鍵入文件名的文本字段。

zenity 文件保存對話框窗口。

用戶可以瀏覽到他在文件系統中選擇的位置,為文件提供名稱,或單擊現有文件以覆蓋它。

選擇現有文件的 zenity 文件保存對話框。

廣告

在上面的示例中,用戶突出顯示了現有文件。

當他單擊“確定”時,會出現一個確認對話框窗口,要求他確認是否要替換現有文件。 請注意文件名出現在警告對話框中。 正是這種對細節的關注賦予了zenity專業的外觀。

如果我們沒有使用--confirm-overwrite選項,該文件將被靜默覆蓋。

zenity 覆蓋確認對話框。

文件的名稱存儲在變量Response中,該變量會打印到終端窗口。

通知對話框窗口

使用zenity ,在您的腳本中包含光滑的通知對話框窗口是毫不費力的。 您可以調用一些常用的對話窗口來為用戶提供信息、警告、錯誤消息和問題。

要創建錯誤消息對話框窗口,請使用以下命令:

 zenity --error --width 300 --text "權限被拒絕。無法寫入文件。"

我們使用的新選項是:

  • –error :告訴zenity我們要使用錯誤對話框窗口。
  • –width設置窗口的初始寬度。

廣告

錯誤對話框窗口以指定的寬度出現。 它使用標準的 GTK 錯誤圖標。

zenity 錯誤對話框窗口。

要創建信息對話窗口,請使用以下命令:

 zenity --info --width 300 --text "更新完成。點擊確定繼續。"

我們使用的新選項是--info ,它告訴zenity創建一個信息對話窗口。

zenity 信息對話窗口。

要創建問題對話窗口,請使用以下命令:

 zenity --question --width 300 --text "你樂意繼續嗎?"; 迴聲$?

我們使用的新選項是--question ,它告訴zenity創建一個問題對話窗口。

$? 是一個特殊的參數。 它保存最近執行的前台管道的返回值。 一般而言,這是來自最近關閉的流程的值。 零值表示“OK”,一個或多個值表示“取消”。

廣告

這是一種通用技術,您可以將其應用於任何zenity對話窗口。 通過在您的腳本中檢查該值,您可以確定從對話窗口返回的數據是否應該被處理或忽略。

zenity 問題對話框。

我們單擊“是”,因此返回代碼為零,表示“確定”。

要創建警告對話框窗口,請使用以下命令:

 zenity --warning --title "硬盤空間不足" --width 300 --text "可能沒有足夠的硬盤空間來保存備份。"

我們使用的新選項是--warning ,它告訴zenity創建一個警告對話框窗口。

出現警告對話框窗口。 這不是一個問題,所以它只有一個按鈕。

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 進度對話框。

我們可以使用管道值到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% 移動。

zenity 進度條對話框窗口。

比例對話框窗口

比例對話框窗口允許用戶移動滑塊來選擇數值。 這意味著她不能輸入太高或太低的值。

我們使用的新選項是:

  • –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。

zenity 比例對話框窗口。

用戶可以移動滑塊來選擇一個新值。

帶有用戶選擇的 zenity 比例對話框

當她單擊“確定”時,該值將傳輸到變量Response並打印到終端窗口。

條目對話窗口

輸入對話窗口允許某人輸入文本。

我們使用的新選項是:

  • –entry :告訴zenity我們要使用一個條目對話窗口。
  • –entry-text如果您想在文本輸入字段中輸入建議值,可以使用它。 我們使用“”來強制一個空字段。 這不是嚴格要求的,但我們想記錄該選項。

完整的命令如下所示:

 Response=$(zenity --entry --text "輸入你的搜索詞" --title "Howe-To Geek" --entry-text=""); 迴聲$響應

將出現一個簡單的對話窗口,其中包含一個文本輸入字段。

zenity 進入對話框窗口。

有人可以鍵入和編輯文本。

zenity 輸入對話框窗口,在文本字段中輸入文本。

當他單擊“確定”時,他鍵入的值將分配給變量 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 

“chmod +x haredware-info.sh in a”終端窗口。

此腳本創建一個臨時文件,文件名保存在 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的輸出通過管道傳輸到teetee將輸出發送到zenityTempFile
  • 該腳本創建一個進度條對話窗口。 它設置對話窗口的寬度和高度,以及標題和提示文本。
  • 該腳本無法預先知道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 腳本帶來專業的感覺。