1 つの一般的な質問に対して 5 つ以上の回答
に応じて
- posix 準拠:一般的なシェル環境を備えた貧弱なシステムでも動作する可能性があります
- bash 固有:いわゆる bashisms の使用
必要に応じて
- 単純な「インライン」の質問/回答 (一般的な解決策)
- ncurses や、libgtk や libqt を使用したよりグラフィカルなインターフェースなど、きれいにフォーマットされたインターフェース...
- 強力な readline 履歴機能を使用
1. POSIX 汎用ソリューション
read
を使用できます コマンドの後に if ... then ... else
が続きます :
printf 'Is this a good question (y/n)? '
read answer
# if echo "$answer" | grep -iq "^y" ;then
if [ "$answer" != "${answer#[Yy]}" ] ;then # this grammar (the #[] operator) means that the variable $answer where any Y or y in 1st position will be dropped if they exist.
echo Yes
else
echo No
fi
(Adam Katz のコメントに感謝:上記のテストを、より移植性が高く、1 つのフォークを回避するものに置き換えました:)
POSIX、ただし重要な機能は 1 つ
ただし、ユーザーが Return を押す必要がないようにしたい場合は、 、次のように書くことができます:
(編集: @JonathanLeffler が正しく示唆しているように、保存 stty の構成は、単に強制的に 正気 にするよりも優れている可能性があります .)
printf 'Is this a good question (y/n)? '
old_stty_cfg=$(stty -g)
stty raw -echo ; answer=$(head -c 1) ; stty $old_stty_cfg # Careful playing with stty
if echo "$answer" | grep -iq "^y" ;then
echo Yes
else
echo No
fi
注: これは、sh、bash、ksh、dash、および busybox でテストされました!
同じですが、y を明示的に待機しています または n :
#/bin/sh
printf 'Is this a good question (y/n)? '
old_stty_cfg=$(stty -g)
stty raw -echo
answer=$( while ! head -c 1 | grep -i '[ny]' ;do true ;done )
stty $old_stty_cfg
if echo "$answer" | grep -iq "^y" ;then
echo Yes
else
echo No
fi
専用ツールの使用
libncurses
を使用して構築された多くのツールがあります 、 libgtk
、 libqt
または他のグラフィカル ライブラリ。たとえば、 whiptail
を使用します :
if whiptail --yesno "Is this a good question" 20 60 ;then
echo Yes
else
echo No
fi
システムによっては、whiptail
を置き換える必要がある場合があります。 別の同様のツールを使用:
dialog --yesno "Is this a good question" 20 60 && echo Yes
gdialog --yesno "Is this a good question" 20 60 && echo Yes
kdialog --yesno "Is this a good question" 20 60 && echo Yes
どこで 20
ダイアログ ボックスの行数と 60
の高さ ダイアログボックスの幅です。これらのツールはすべてほぼ同じ 構文。
DIALOG=whiptail
if [ -x /usr/bin/gdialog ] ;then DIALOG=gdialog ; fi
if [ -x /usr/bin/xdialog ] ;then DIALOG=xdialog ; fi
...
$DIALOG --yesno ...
2. Bash 固有のソリューション
基本インライン メソッド
read -p "Is this a good question (y/n)? " answer
case ${answer:0:1} in
y|Y )
echo Yes
;;
* )
echo No
;;
esac
case
を使用したい yes | ja | si | oui
をテストすることもできました 必要に応じて...
インライン 単一キー 特徴
bash では、read
の意図する入力の長さを指定できます。 コマンド:
read -n 1 -p "Is this a good question (y/n)? " answer
bash では read
コマンドはタイムアウトを受け入れます
read -t 3 -n 1 -p "Is this a good question (y/n)? " answer
[ -z "$answer" ] && answer="Yes" # if 'yes' have to be default choice
3. 専用ツールのコツ
単純な yes - no
を超えた、より洗練されたダイアログ ボックス 目的:
dialog --menu "Is this a good question" 20 60 12 y Yes n No m Maybe
プログレスバー:
dialog --gauge "Filling the tank" 20 60 0 < <(
for i in {1..100};do
printf "XXX\n%d\n%(%a %b %T)T progress: %d\nXXX\n" $i -1 $i
sleep .033
done
)
小さなデモ:
#!/bin/sh
while true ;do
[ -x "$(which ${DIALOG%% *})" ] || DIALOG=dialog
DIALOG=$($DIALOG --menu "Which tool for next run?" 20 60 12 2>&1 \
whiptail "dialog boxes from shell scripts" >/dev/tty \
dialog "dialog boxes from shell with ncurses" \
gdialog "dialog boxes from shell with Gtk" \
kdialog "dialog boxes from shell with Kde" ) || exit
clear;echo "Choosed: $DIALOG."
for i in `seq 1 100`;do
date +"`printf "XXX\n%d\n%%a %%b %%T progress: %d\nXXX\n" $i $i`"
sleep .0125
done | $DIALOG --gauge "Filling the tank" 20 60 0
$DIALOG --infobox "This is a simple info box\n\nNo action required" 20 60
sleep 3
if $DIALOG --yesno "Do you like this demo?" 20 60 ;then
AnsYesNo=Yes; else AnsYesNo=No; fi
AnsInput=$($DIALOG --inputbox "A text:" 20 60 "Text here..." 2>&1 >/dev/tty)
AnsPass=$($DIALOG --passwordbox "A secret:" 20 60 "First..." 2>&1 >/dev/tty)
$DIALOG --textbox /etc/motd 20 60
AnsCkLst=$($DIALOG --checklist "Check some..." 20 60 12 \
Correct "This demo is useful" off \
Fun "This demo is nice" off \
Strong "This demo is complex" on 2>&1 >/dev/tty)
AnsRadio=$($DIALOG --radiolist "I will:" 20 60 12 \
" -1" "Downgrade this answer" off \
" 0" "Not do anything" on \
" +1" "Upgrade this anser" off 2>&1 >/dev/tty)
out="Your answers:\nLike: $AnsYesNo\nInput: $AnsInput\nSecret: $AnsPass"
$DIALOG --msgbox "$out\nAttribs: $AnsCkLst\nNote: $AnsRadio" 20 60
done
もっとサンプル? USB デバイスと USB リムーバブル ストレージ セレクターを選択するためのwhiptail の使用をご覧ください:USBKeyChooser
5. readline の履歴の使用
例:
#!/bin/bash
set -i
HISTFILE=~/.myscript.history
history -c
history -r
myread() {
read -e -p '> ' $1
history -s ${!1}
}
trap 'history -a;exit' 0 1 2 3 6
while myread line;do
case ${line%% *} in
exit ) break ;;
* ) echo "Doing something with '$line'" ;;
esac
done
これにより、ファイル .myscript.history
が作成されます あなたの $HOME
で Up などの readline の履歴コマンドを使用するよりも、 、ダウン , Ctrl +r
シェル プロンプトでユーザー入力を取得する最も簡単で最も広く利用されている方法は、read
です。 指図。その使用法を説明する最良の方法は、簡単なデモンストレーションです:
while true; do
read -p "Do you wish to install this program? " yn
case $yn in
[Yy]* ) make install; break;;
[Nn]* ) exit;;
* ) echo "Please answer yes or no.";;
esac
done
Steven Huwig が指摘したもう 1 つの方法は、Bash の select
です。 指図。 select
を使用した同じ例を次に示します。 :
echo "Do you wish to install this program?"
select yn in "Yes" "No"; do
case $yn in
Yes ) make install; break;;
No ) exit;;
esac
done
select
で 入力をサニタイズする必要はありません。利用可能な選択肢が表示され、選択肢に対応する数字を入力します。また、自動的にループするため、while true
は必要ありません。 無効な入力があった場合、ループして再試行します。
また、Léa Gris は、回答の中で言語にとらわれないリクエストを作成する方法を示しました。最初の例を複数の言語により適切に適応させると、次のようになります。
set -- $(locale LC_MESSAGES)
yesexpr="$1"; noexpr="$2"; yesword="$3"; noword="$4"
while true; do
read -p "Install (${yesword} / ${noword})? " yn
if [[ "$yn" =~ $yesexpr ]]; then make install; exit; fi
if [[ "$yn" =~ $noexpr ]]; then exit; fi
echo "Answer ${yesword} / ${noword}."
done
明らかに、他の通信文字列 (インストール、応答) はここでは未翻訳のままであり、より完全な翻訳で対処する必要がありますが、多くの場合、部分的な翻訳でも役立ちます。
最後に、F. Hauri による優れた回答をご覧ください。
echo "Please enter some input: "
read input_variable
echo "You entered: $input_variable"