Linux シェル スクリプトに GUI を追加する方法
Bash スクリプトでは、GUI ウィンドウ、スライダー、ラジオ ボタン、プログレス バーなどを使用できます。 zenity ツールキットの使用方法と、Bash スクリプトの改良方法を学びます。その方法をご紹介します。
Bash スクリプトは強力なプログラミング言語であり、Bash シェルに組み込まれているため、誰でも簡単に利用できます。これはプログラミングを始めるのが簡単な言語です。解釈されるため、スクリプトをコンパイルする必要はありません。スクリプト ファイルを編集して実行可能にすると、すぐに実行できるようになります。これにより、コーディング、実行、デバッグのサイクルが非常に効率的になります。
Bash スクリプトに関して人々が抱いている主な不満は 2 つあります。1 つ目は速度です。 Bash シェルはスクリプト内のコマンドを解釈するため、コンパイルされたコードほど高速には実行されません。しかし、これはトラクターが車ほど速くないと文句を言うようなものです。それらはさまざまな目的で使用されます。
ただし、速度には 2 種類あります。多くの場合、簡単なスクリプトをまとめて使用すると、C などのコンパイル言語でソリューションを開発するよりもはるかに迅速にタスクを実行できます。
Bash スクリプトに関して人々が抱く 2 番目の不満は、ユーザー インターフェイス、つまりターミナル ウィンドウです。もちろん、インターフェースが重要でない場合もあります。スクリプトを使用するのがその作成者だけであれば、インターフェイスはおそらくそれほど重要ではありません。バックグラウンドおよびバッチタイプの処理を実行するスクリプトにも関係ありません。通常、このようなスクリプトでは、ユーザーの操作は (あったとしても) あまり必要ありません。
場合によっては、ターミナル ウィンドウよりももう少し直観的で最新のものが必要になることがあります。ほとんどの人は、グラフィカル ユーザー インターフェイス (GUI) に精通しています。できるだけスムーズなエクスペリエンスを人々に提供するには、スクリプトから GUI 要素を作成して使用する必要があります。
zenity アプリケーション
zenity を使用すると、Bash スクリプトに幅広いグラフィカル インターフェイス要素を組み込むことができます。これは、スクリプトにモダンな雰囲気と現代的で見慣れた外観を与える強力なツールキットです。
zenity は、Ubuntu、Fedora、Manjaro ディストリビューションにプレインストールされています。これは GNOME の一部です。 KDE を使用している場合は、代わりに kdialog をチェックしてみてください。ただし、 zenity はどのデスクトップ環境でも実行できます。
この記事の例では、コマンド ラインからさまざまなダイアログ ウィンドウを作成する方法、戻り値とユーザーの選択を変数に取り込む方法、およびスクリプトでダイアログ ウィンドウを使用する方法を示します。
最後に、3 種類のダイアログ ウィンドウをすべて使用する小さなアプリケーションを作成します。
カレンダーダイアログウィンドウ
カレンダー ダイアログ ウィンドウを使用すると、日付を選択できます。 zenity を使用して作成するには、2 つの単語からなる単一のコマンドが必要です。
zenity --calendarカレンダーダイアログウィンドウが表示されます。これには、標準の日付ピッカーに期待されるすべての機能が含まれています。月と年を変更し、日をクリックしてその日付を選択できます。デフォルトでは、ウィンドウが表示されると今日の日付が強調表示されます。
「OK」をクリックしてダイアログウィンドウを閉じ、強調表示された日付を選択します。日付をダブルクリックしても同じことが行われます。
日付を選択しない場合は、「キャンセル」をクリックするか、キーボードの「Esc」キーを押すか、ダイアログウィンドウを閉じてください。
上の例では、2019 年 8 月 19 日が選択されています。ユーザーが「OK」をクリックすると、カレンダーが閉じ、選択した日付が端末ウィンドウに印刷されます。
「GTKDialog は一時的な親なしでマップされました。」という行は無視してください。これはお勧めできません。」
GTK は GIMP Tool Kit の略で、GNOME インターフェイスの開発に使用されるツールキットです。これは元々、GNU 画像操作プログラム (GIMP) の作者によって考案されました。 GNU は GNU の Not Unix の略です。
GTK エンジンは、zenity の作成者に、GTK コンポーネントを標準外の方法で使用したことを警告しています。
日付値の取得
日付を端末に出力しても、あまり役に立ちません。このカレンダーをスクリプトの 1 つから呼び出す場合は、選択した日付値をキャプチャして、スクリプト内でそれを使って何か役立つことができるようにする必要があります。カレンダーも少しカスタマイズしてみます。
カレンダーでは次のオプションを使用します。これらはすべて、二重ダッシュ「-」フラグと一緒に使用する必要があります。
- –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); echo $ChosenDateこれで、カレンダーにプロンプトとウィンドウのタイトルが表示されます。日付は今日の日付ではなく、選択した開始日に設定されます。
選択時に返される日付文字列の形式をカスタマイズすることもできます。 --date-format オプションの後には形式指定子を続ける必要があります。これは、出力に含まれるデータと形式を定義するトークンの文字列です。トークンは strftime() C 言語関数で使用されるものと同じであり、その選択肢は膨大です。
私たちが使用しているトークンは次のとおりです。
- %A: 曜日の完全な名前。
- %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 は、これらすべての機能やその他の機能を提供します。カレンダー ダイアログ ウィンドウと同じくらい使いやすいです。
使用する新しいオプションは次のとおりです。
- –file-selection: ファイル選択ダイアログ ウィンドウを使用することを
zenityに指示します。 - –multiple: ユーザーが複数のファイルを選択できるようにします。
- –file-filter: ファイル ダイアログ ウィンドウに表示するファイル タイプを指示します。
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."私たちが使用している新しいオプションは次のとおりです。
- –error:
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 に質問ダイアログ ウィンドウを作成するように指示します。
$? は特別なパラメータです。これは、最後に実行されたフォアグラウンド パイプラインからの戻り値を保持します。一般的に、これは最後に終了したプロセスからの値です。値が 0 の場合は「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に進行状況ダイアログ ウィンドウを使用するように指示します。 - –auto-close: 進行状況バーが 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 \25\など、数字を含むecho行もzenityによって受け入れられ、次の値を設定します。進行状況バー。- ワークリスト関数が呼び出され、
zenityにパイプされます。
次のコマンドを使用して、スクリプトを実行可能にします。
chmod +x progress.sh次のコマンドを使用してスクリプトを実行します。
./progress.shスクリプトが実行され、スクリプトの各フェーズが実行されるにつれてテキスト メッセージが変化します。進行状況バーは 100% に向かって段階的に移動します。
スケールダイアログウィンドウ
スケール ダイアログ ウィンドウを使用すると、スライダーを移動して数値を選択できます。これは、高すぎる値も低すぎる値も入力できないことを意味します。
私たちが使用している新しいオプションは次のとおりです。
- –scale:
zenityにスケール ダイアログ ウィンドウを使用するように指示します。 - –min-value: スケールの最小値を設定します。
- –max-value: スケールの最大値を設定します。
- –step: 矢印キーを使用したときにスライダーが移動する量を設定します。誰かがマウスを使用している場合、これはスライダーの動きには影響しません。
- –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に入力ダイアログ ウィンドウを使用するように指示します。 - –entry-text: テキスト入力フィールドに推奨値を入力する場合にこれを使用できます。 「」を使用して空のフィールドを強制します。これは厳密には必須ではありませんが、オプションを文書化したいと考えました。
完全なコマンドは次のようになります。
Response=$(zenity --entry --text "Enter your search term" --title "Howe-To Geek" --entry-text=""); echo $Responseテキスト入力フィールドを含む単純なダイアログ ウィンドウが表示されます。
誰かがテキストを入力して編集できます。
「OK」をクリックすると、入力した値が変数 Response に割り当てられます。 echo を使用して変数の値をターミナル ウィンドウに出力します。
すべてを一緒に入れて
これらのテクニックを組み合わせて、機能的なスクリプトを作成してみましょう。スクリプトはハードウェア情報スキャンを実行し、結果をスクロールするテキスト ウィンドウでユーザーに表示します。長いスキャン タイプまたは短いスキャン タイプを選択できます。
このスクリプトでは、3 種類のダイアログ ウィンドウを使用します。そのうち 2 つは初めてのものです。
- 1 つ目はリスト ダイアログ ウィンドウです。誰かが選択できるようになります。
- 2 つ目は進行状況ダイアログ ウィンドウで、何かが起こっているので待つ必要があることをユーザーに知らせます。
- 3 番目はテキスト情報ウィンドウで、結果がユーザーに表示されます。
このテキストをエディタに入力し、「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オプションにより、最初の列がラジオ ボタンの列になります。 - ウィンドウのタイトルとテキスト プロンプトを設定します。
- 最初の列のタイトルを「選択」に設定します。この列のコンテンツはラジオ ボタンになります。
- 2 番目の列のタイトルを「選択」に設定し、2 番目の列の内容を提供します。この列には、「短い」と「長い」という 2 つのテキスト ラベルが保持されます。 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 スキャンが完了すると、スクリプトは zenity を呼び出して、--text-info オプションを使用してテキスト情報ダイアログ ウィンドウを作成します。テキスト情報ダイアログ ウィンドウに、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 スクリプトにプロフェッショナルなタッチを与えることができることを認めざるを得ません。