LinuxシェルスクリプトにGUIを追加する方法
BashスクリプトでGUIウィンドウ、スライダー、ラジオボタン、プログレスバーなどを使用できます。zenityツールキットの使い方を学び、Bashスクリプトに新しい外観を与えましょう。方法をお教えします。
Bashスクリプトは強力なプログラミング言語であり、Bashシェルに組み込まれているため、誰でも簡単に利用できます。プログラミングを始めるのが簡単な言語です。解釈されるため、スクリプトをコンパイルする必要はありません。スクリプトファイルを編集して実行可能にしたら、すぐに実行できます。これにより、コーディング、実行、デバッグのサイクルが非常に効率的になります。
Bashスクリプトに対する主な不満は二つあり、最初は速度です。Bashシェルはスクリプト内のコマンドを解釈するため、コンパイルされたコードよりも実行が遅くなります。しかし、これはトラクターが車ほど速くないと不満を言うようなもので、両者は異なる目的のために作られています。
ただし、スピードには2種類あります。しばしば、迅速なスクリプトを組み合わせて、Cなどのコンパイル言語でソリューションを開発するよりも、はるかに迅速にタスクを実行するために使用できます。
Bashスクリプトに対する2つ目の不満はユーザーインターフェースです---それは端末ウィンドウです。もちろん、時にはインターフェースが重要でないこともあります。スクリプトを使用するのがその作成者だけなら、インターフェースはそれほど重要ではないでしょう。また、バックグラウンドやバッチ処理を行うスクリプトにとっても、インターフェースは重要ではありません。通常、そのようなスクリプトは多くの(もしあれば)ユーザーのインタラクションを必要としません。
ターミナルウィンドウよりも直感的で現代的なものが必要な場合があります。ほとんどの人はグラフィカルユーザーインタフェース(GUI)に慣れています。できるだけスムーズな体験を提供するためには、スクリプトからGUI要素を作成して使用する必要があります。
ゼニティアプリケーション
zenityは、Bashスクリプトに多種多様なグラフィカルインターフェース要素を組み込むことを可能にします。それは、スクリプトに現代的な感覚と現代的で親しみやすい外観を与える強力なツールキットです。
zenity は、Ubuntu、Fedora、および Manjaro ディストリビューションにプリインストールされています。これは GNOME の一部です。KDE を使用している場合は、確認してみると良いでしょう。
kdialogその代わりに、zenityはどのデスクトップ環境でも動作しますが。
この記事の例では、コマンドラインから異なるダイアログウィンドウを作成する方法、返り値やユーザーの選択を変数にキャプチャする方法、スクリプト内でダイアログウィンドウを使用する方法を示しています。
私たちは、3種類のダイアログウィンドウすべてを使う小さなアプリケーションで終わります。
カレンダー ダイアログ ウィンドウ
カレンダーダイアログウィンドウは、日付を選択することを可能にします。zenityを使用してこれを作成するには、二つの言葉からなる一つのコマンドが必要です。
zenity --calendarカレンダーダイアログウィンドウが表示されます。ここには、標準のデートピッカーから期待されるすべての機能があります。月と年を変更することができ、日付をクリックしてその日を選択することができます。デフォルトでは、ウィンドウが表示されたときに今日の日付がハイライトされます。
「OK」をクリックしてダイアログウィンドウを閉じ、ハイライトされた日付を選択します。日付をダブルクリックすると同じことができます。
日付を選択したくない場合は、「キャンセル」をクリックするか、キーボードの「Esc」キーを押すか、ダイアログウィンドウを閉じてください。
上記の例では、2019年8月19日が選択されています。ユーザーが「OK」をクリックすると、カレンダーが閉じ、選択した日付がターミナルウィンドウに表示されます。
「GTKDialogは、一時的な親なしでマッピングされました。このことは推奨されません。」という行は無視してもかまいません。
GTKはGIMPツールキットを指し、GNOMEインターフェースを開発するために使用されるツールキットです。これは元々、GNU画像加工プログラム(GIMP)の著者によって考案されました。GNUは「GNUはUnixではない」の略です。
GTKエンジンは、zenityの作者に対して、GTKコンポーネントを非標準の方法で使用していることを警告しています。
日付値の取得
端末に日付を印刷することは、私たちにとってあまり意味がありません。このカレンダーをスクリプトの一つから呼び出す場合、選択された日付の値を取得して、それをスクリプト内で何か有用なことに活用する必要があります。また、カレンダーを少しカスタマイズします。
カレンダーには以下のオプションを使用します。これらはすべてダブルダッシュ "--" フラグと一緒に使用する必要があります:
- --テキスト: カレンダーに表示するテキストの文字列を指定します。デフォルトの「以下から日付を選択してください。」を置き換えます。
- --タイトル: カレンダーダイアログウィンドウのタイトルを設定します。
- --day: カレンダーが開くときに選択される日を設定します。
- --月 : カレンダーが開くときに選択される月を設定します。
- --年: カレンダーが開くときに選択される年を設定します。
私たちはカレンダーから返された日付を取得するために、ChosenDateという変数を使用しています。そして、その日付をターミナルウィンドウに出力するために、echo $ChosenDateを使用しています。
はい、前の例でも同じ結果を達成しましたが、ここでは選択した日付が変数に保存されています。前の例では、それが印刷され、忘れられていました。
ChosenDate=$(zenity -- calendar --text "Choose a date" --title "How-To Geek Rota" --day 1 -- month 9 --year 2019); echo $ChosenDate今、カレンダーには私たちのプロンプトとウィンドウタイトルが表示されています。日付は今日の日付ではなく、私たちが選んだ開始日になっています。
選択が行われたときに返される日付文字列の形式もカスタマイズできます。--date-formatオプションの後には形式指定子が必要です。これは、出力に含めるデータと形式を定義するトークンの文字列です。トークンは、strftime() C言語関数と同じものであり、非常に多くの選択肢があります。
私たちが使用しているトークンは次の通りです:
- 曜日のフルネーム。
- %d: 日の数字としての日付。
- %m: 月を数字で表したもの。
- %y: 年の下2桁(世紀は含まない).
ChosenDate=$(zenity -- calendar --text "Choose a date" --title "How-To Geek Rota" --date-format="%A %d/%m/%y" --day 1 -- month 9 --year 2019); echo $ChosenDate誰かが日付を選択します:
そして、日付は私たちのフォーマットで返されます。それは曜日の名前を表示し、その後にヨーロッパ式の順序で日、月、年が続きます。
ファイル選択ダイアログウィンドウ:ファイルの選択
ファイル選択ダイアログウィンドウは非常に複雑です。人々はファイルシステムをブラウズし、1つまたは複数のファイルをハイライトし、その後「OK」をクリックしてそれらのファイルを選択するか、選択をキャンセルすることができます。
zenity はこのすべての機能を提供し、さらに多くのことができます。また、カレンダーダイアログウィンドウと同じくらい使いやすいです。
私たちが使用する新しいオプションは次のとおりです:
- --ファイル選択:
zenityにファイル選択ダイアログウィンドウを使用したいことを伝えます。 - --複数: それにより、ユーザーは複数のファイルを選択できます。
- --ファイルフィルター: ファイルダイアログウィンドウに表示するファイルタイプを指示します。
zenity --file-selection --tile "How-To Geek" --multiple --file-filter='*.mm *.png *.page *.sh *.txt'ファイル選択ダイアログウィンドウは、他のファイル選択ウィンドウと同様に機能しています。
ユーザーはファイルシステムを閲覧し、好みのファイルを選択することができます。
新しいディレクトリに移動し、「button_hybrid.png」というファイルを選択しました。
「OK」をクリックすると、ファイル選択ダイアログウィンドウが閉じ、ファイル名とパスがターミナルウィンドウに表示されます。
もし今後の処理でファイル名を使用する必要がある場合は、カレンダーからの日付と同様に、それを変数にキャプチャすることができます。
ファイル選択ダイアログウィンドウ:ファイルの保存
オプションを1つ追加すれば、ファイル選択ダイアログウィンドウをファイル保存ダイアログウィンドウに変えることができます。そのオプションは --save です。また、--confirm-overwrite オプションも使用します。これにより、既存のファイルを上書きしたいかどうかを確認するプロンプトが表示されます。
Response=$(zenity --file-selection --save --confirm-overwrite); echo $Responseファイル保存ダイアログウィンドウが表示されます。ファイル名を入力できるテキストフィールドがあることに注意してください。
ユーザーはファイルシステム内の任意の場所に移動し、ファイル名を指定するか、既存のファイルをクリックして上書きすることができます。
上記の例では、ユーザーが既存のファイルを強調表示しました。
彼が「OK」をクリックすると、既存のファイルを置き換えることを確認するように求める確認ダイアログウィンドウが表示されます。警告ダイアログにはファイルの名前が表示されます。これが、zenity にプロフェッショナルな外観を与える細部への注意の一例です。
もし--confirm-overwriteオプションを使用していなかったら、ファイルは黙って上書きされていたでしょう。
ファイルの名前は変数Responseに格納されており、それがターミナルウィンドウに表示されます。
通知ダイアログウィンドウ
zenityを使用すれば、スクリプトに洗練された通知ダイアログウィンドウを簡単に組み込むことができます。情報、警告、エラーメッセージ、ユーザーへの質問のために呼び出せる標準のダイアログウィンドウがあります。
エラーメッセージダイアログウィンドウを作成するには、次のコマンドを使用します:
zenity --error --width 300 --text "Permission denied. Cannot write to the file."私たちが使用している新しいオプションは次のとおりです:
- --エラー:
zenityにエラーダイアログウィンドウを使用したいことを伝えます。 - --width: ウィンドウの初期幅を設定します。
エラーダイアログウィンドウは指定された幅で表示されます。標準のGTKエラーアイコンを使用しています。
情報ダイアログウィンドウを作成するには、次のコマンドを使用します:
zenity --info --width 300 --text "Update complete. Click OK to continue."私たちが使用している新しいオプションは --info で、これは zenity に情報ダイアログウィンドウを作成するよう指示します。
質問ダイアログウィンドウを作成するには、次のコマンドを使用します:
zenity --question --width 300 --text "Are you happy to proceed?"; echo $?私たちが使用している新しいオプションは--questionで、これによりzenityは質問ダイアログウィンドウを作成することができます。
この$?は特別なパラメータです。これは、最近実行されたフォアグラウンドパイプラインからの戻り値を保持します。一般的には、これは最近終了したプロセスの値です。ゼロの値は「OK」を意味し、1以上の値は「キャンセル」を意味します。
これは、zenityダイアログウィンドウのいずれにも適用できる一般的なテクニックです。この値をスクリプトでチェックすることで、ダイアログウィンドウから返されたデータを処理すべきか無視すべきかを判断できます。
「はい」をクリックしたので、リターンコードはゼロで「OK」を示しています。
警告ダイアログウィンドウを作成するには、次のコマンドを使用します:
zenity --warning --title "Low Hard Drive Space" --width 300 --text "There may not be enough hard drive space to save the backup."私たちが使用している新しいオプションは --warning で、これにより zenity が警告ダイアログウィンドウを作成します。
警告ダイアログウィンドウが表示されます。これは質問ではないため、ボタンは1つしかありません。
進捗ダイアログウィンドウ
zenityのプログレスダイアログウィンドウを使用して、スクリプトの完了までどれくらい進んでいるかを示すプログレスバーを表示できます。
プログレスバーは、スクリプトからパイプで渡される値に応じて進行します。この原則を示すために、次のコマンドを使用してください:
(for i in $(seq 0 10 100); do echo $i; sleep 1; done)コマンドは次のように分解されます:
seqコマンドは、0 から 100 までを 10 ごとのステップで進みます。- 各ステップで、値は変数
iに保存されます。これがターミナルウィンドウに印刷されます。 - そのコマンドは、
sleep 1コマンドによって1秒間停止します。
これを使って、zenity プログレスダイアログウィンドウでプログレスバーを示すことができます。前のコマンドの出力を zenity: にパイプしていることに注意してください。
(for i in $(seq 0 10 100); do echo $i; sleep 1; done) | zenity --progress --title "How-To Geek" -- auto-close私たちが使用している新しいオプションは次のとおりです:
- --progress:
zenityに進行状況ダイアログウィンドウを使用したいことを伝えます。 - --自動閉鎖: プログレスバーが100パーセントに達するとダイアログを閉じます。
進捗ダイアログウィンドウが表示され、バーが100パーセントに向かって進み、各ステップの間で1秒間一時停止します。
スクリプトに進行状況ダイアログウィンドウを含めるために、zenity に値をパイプするという概念を使用できます。
このテキストをエディタに入力し、「progress.sh」として保存します。
!/bin/bash
function work-list () {
echo "# First work item"
echo "25"
sleep 1
echo "# Second work item"
echo "50"
sleep 1
echo "# Third work item"
echo "75"
sleep 1
echo "# Last work item"
echo "100"
sleep 1
}
work-list | zenity --progress --title "How-To Geek" --auto-close
exit 0
こちらがスクリプトの内訳です:
- スクリプトでは、
work-listという関数が定義されています。ここに、実際の作業を行うためのコマンドや指示を記入します。すべてのsleep 1コマンドをあなたの実際のコマンドに置き換えてください。 zenityはecho "# ..."の行を受け入れ、進行状況ダイアログウィンドウ内に表示します。これらの行のテキストを変更して、ユーザーに有益なメッセージを伝えるようにしてください。echo行に含まれる数字、例えばecho "25"のようなものは、zenityにも受け入れられ、プログレスバーの値を設定します。- 作業リスト機能が呼び出され、
zenityにパイプされます。
このコマンドを使用してスクリプトを実行可能にします:
chmod +x progress.shスクリプトを実行するには、このコマンドを使用してください:
./progress.shスクリプトが実行され、スクリプトの各フェーズが実行されるごとにテキストメッセージが変更されます。進行バーは100パーセントに向かって段階的に移動します。
スケールダイアログウィンドウ
スケールダイアログウィンドウでは、スライダーを動かして数値を選択できるようになっています。これは、彼女が高すぎるまたは低すぎる値を入力できないことを意味します。
私たちが使用している新しいオプションは次のとおりです:
- --scale:
zenityにスケールドialogウィンドウを使用することを通知します。 - --min-value: スケールの最小値を設定します。
- --max-value: スケールの最大値を設定します。
- --ステップ:矢印キーが使用されたときにスライダーが動く量を設定します。これは、誰かがマウスを使用した場合のスライダーの動きには影響しません。
- --value: スライダーの初期値と位置を設定します。
これが私たちが使用しているコマンドです:
Response=$(zenity --scale --title "How-To Geek" --text "Select magnification." --min-value=0 --max-value=30 --step=3 --value15); echo $Responseスライダーダイアログウィンドウが表示され、スライダーは15に設定されています。
ユーザーはスライダーを動かして新しい値を選択できます。
彼女が「OK」をクリックすると、値が変数Responseに転送され、ターミナルウィンドウに印刷されます。
エントリーダイアログウィンドウ
エントリーダイアログウィンドウは、誰かがテキストを入力できるようにします。
私たちが使用している新しいオプションは次のとおりです:
- --entry:
zenityにエントリーダイアログウィンドウを使用したいことを伝えます。 - --エントリーテキスト: テキスト入力フィールドに提案された値を入力したい場合は、これを使用できます。「」を使って空のフィールドを強制しています。これは厳密に必要ではありませんが、オプションを文書化したかったのです。
完全なコマンドはこのようになります:
Response=$(zenity --entry --text "Enter your search term" --title "Howe-To Geek" --entry-text=""); echo $Responseシンプルなダイアログウィンドウが表示され、テキスト入力フィールドが含まれています。
誰かがテキストを入力し、編集できます。
彼が「OK」をクリックすると、彼が入力した値が変数Responseに割り当てられます。私たちはechoを使って、ターミナルウィンドウに変数の値を表示します。
すべてをまとめる
これらの技術を組み合わせて、機能するスクリプトを作成しましょう。このスクリプトはハードウェア情報をスキャンし、結果をスクロールするテキストウィンドウでユーザーに提示します。彼女は長いスキャンタイプまたは短いスキャンタイプを選ぶことができます。
このスクリプトでは、3種類のダイアログウィンドウを使用しますが、そのうちの2つは私たちにとって新しいものです:
- 最初はリストダイアログウィンドウです。それは誰かが選択をすることを可能にします。
- 二番目は進行状況ダイアログウィンドウで、ユーザーに何かが起こっていることを知らせ、待つべきであることを示します。
- 三つ目はテキスト情報ウィンドウで、ユーザーに結果を表示します。
このテキストをエディタに入力し、「hardware-info.sh」として保存してください。
#!/bin/bash
Display hardware listing for this computer
TempFile=$(mktemp)
ListType=`zenity --width=400 --height=275 --list --radiolist \
--title 'Hardware Scan' \
--text 'Select the scan type:' \
--column 'Select' \
--column 'Scan Type' TRUE "Short" FALSE "Long"`
if [[ $? -eq 1 ]]; then
# they pressed Cancel or closed the dialog window
zenity --error --title="Scan Declined" --width=200 \
--text="Hardware scan skipped"
exit 1
elif [ $ListType == "Short" ]; then
# they selected the short radio button
Flag="--short"
else
# they selected the long radio button
Flag=""
fi
search for hardware info with the appropriate value in $Flag
hwinfo $Flag | tee >(zenity --width=200 --height=100 \
--title="Collating Information" --progress \
--pulsate --text="Checking hardware..." \
--auto-kill --auto-close) >${TempFile}
Display the hardware info in a scrolling window
zenity --width=800 --height=600 \
--title "Hardware Details" \
--text-info --filename="${TempFile}"
exit 0
これを実行可能にするためにこのコマンドを使用してください:
chmod +x hardware-info.shこのスクリプトは一時ファイルを作成し、そのファイルの名前はTempFile変数に保持されています。
TempFile=$(mktemp)スクリプトは、--listオプションを使用して、リストダイアログウィンドウと呼ばれるzenityダイアログウィンドウを作成します。行の最後の"\"文字は、スクリプトにそれらをラップしている1つの長い行として扱うように指示します。プロセスは次のとおりです:
- ウィンドウの幅と高さを指定します。
- リストダイアログウィンドウは、列をサポートしています。
--radiolistオプションを使用すると、最初の列はラジオボタンの列になります。 - ウィンドウのためにタイトルとテキストプロンプトを設定しました。
- 最初の列のタイトルを「選択」に設定します。この列の内容はラジオボタンになります。
- 第二列のタイトルを「選択」と設定し、第二列の内容を提供します。この列には「短い」と「長い」という二つのテキストラベルがあります。TRUEおよびFALSEのインジケーターは、ダイアログウィンドウが表示されたときに「短い」オプションがデフォルトで選択されていることを意味します。
- このダイアログウィンドウからの結果を
ListTypeという変数に保存しています。
ListType=`zenity --width=400 --height=275 --list --radiolist \
--title 'Hardware Scan' \
--text 'Select the scan type:' \
--column 'Select' \
--column 'Scan Type' TRUE "Short" FALSE "Long"`
ユーザーが「キャンセル」を押した場合、ListTypeの値を確認する必要はなく、単に終了できます。「OK」を押した場合、彼が「ショート」または「ロング」のラジオボタンを選択したかどうかを確認する必要があります:
- 特別なパラメータ
$?は、ユーザーが「OK」を押した場合はゼロになります。「キャンセル」を押したりウィンドウを閉じたりした場合は、1になります。 - もしそれが1と等しい場合、スクリプトはエラー情報ダイアログウィンドウを表示し、終了します。「OK」を押すと、
ListType変数の値をテストするために進みます。 - もし
ListType変数が"Short"の値を保持している場合、スクリプトはFlagという変数を"--short."に設定します。 - もし
ListType変数が値「Short」を保持していない場合、値「Long」を保持している必要があります。このスクリプトは、Flagという変数を空の文字列「」に設定します。 - スクリプトは次のセクションで
Flag変数を使用します。
if [[ $? -eq 1 ]]; then
# they pressed Cancel or closed the dialog window
zenity --error --title="Scan Declined" --width=200 \ --text="Hardware scan skipped"
exit 1
elif [ $ListType == "Short" ]; then
# they selected the short radio button
Flag="--short"
else
# they selected the long radio button
Flag=""
fi
スクリプトがユーザーが望むスキャンのタイプを知ったので、ハードウェア情報スキャンを実行できます。
- スクリプトは
hwinfoコマンドを呼び出し、Flag変数の値を渡します。 - もし
Flagが「--short」を含む場合、hwinfoコマンドは短いスキャンを実行します。Flagの値が「」の場合、何もhwinfoに渡されず、デフォルトの長いスキャンが実行されます。 - スクリプトは、
hwinfoの出力をteeにパイプします。teeは、出力をzenityとTempFileに送ります。 - スクリプトはプログレスバーのダイアログウィンドウを作成します。ダイアログウィンドウの幅と高さ、タイトル、プロンプトテキストを設定します。
- スクリプトは事前に
hwinfoコマンドがどれくらいの情報を生成するかを知ることができないため、プログレスバーを正しく100パーセントまで進めることができません。--pulsateオプションは、プログレスダイアログに動くインジケーターを表示させます。これにより、ユーザーに何かが起こっていることが通知され、待つべきであることを伝えます。 --auto-killオプションは、誰かが「キャンセル」をクリックした場合にスクリプトを終了します。--auto-closeオプションは、監視しているプロセスが完了すると進行状況ダイアログを自動的に閉じるようにします。
search for hardware info with the appropriate value in $Flag
hwinfo $Flag | tee >(zenity --width=200 --height=100 \
--title="Collating Information" --progress \
--pulsate --text="Checking hardware..." \
--auto-kill --auto-close) >${TempFile}
hwinfoのスキャンが完了すると、スクリプトは--text-infoオプションを使用してテキスト情報ダイアログウィンドウを作成するためにzenityを呼び出します。テキスト情報ダイアログウィンドウには、TempFileファイルの内容が表示されます:
- スクリプトはダイアログウィンドウの幅と高さ、およびタイトルテキストを設定します。
--flenameオプションは、TempFIle変数に保持されているファイルの内容を読み取るために使用されます。
Display the hardware info in a scrolling window
zenity --width=800 --height=600 \
--title "Hardware Details" \
--text-info --filename="${TempFile}"
ユーザーがテキスト情報ダイアログウィンドウを閉じると、スクリプトが終了します。
exit 0それを始めて見てみましょう。
./hardware-info.shリストボックスが表示されます。デフォルトでは「ショート」オプションが選択されています。
「ロング」を選択して、次に「OK」をクリックしましょう。
進行状況ウィンドウがスライドインジケーターと共に表示されます。ハードウェアスキャンが完了するまで画面に表示されたままになります。
ハードウェアスキャンが完了すると、スキャンの詳細が表示されたテキスト情報ダイアログウィンドウが表示されます。
「OK」をクリックしてください。
どんなにコマンドラインを愛する人でも、いくつかのGUIダイアログウィンドウが控えめなBashスクリプトにプロフェッショナルな印象を与えることを認めざるを得ません。