これが私の状況です。3 つの入力を検証しようとしています。最初の入力と 2 番目の入力では、正しい入力を求められません。何が問題なのでしょうか?
#!/bin/bash
while :
do
echo "Please enter your tittle:"
read TITTLE
echo "Please enter your surname:"
read SURNAME
echo "Please enter your ID No."
read ID
if [ "$TITTLE" = "" ] || [ "${TITTLE//[!0-9]}" != "" ];
then
echo "Enter your valid tittle without special characters."
echo "Please try again."
exit 1
fi
if [ "$SURNAME" = "" ] || [ "${SURNAME//[!0-9]}" != "" ];
then
echo "Enter your valid surname without special characters."
echo "Please try again."
exit 1
fi
if [ "$ID" = "" ] || [ "${ID//[0-9]}" != "" ];
then
echo "Enter your valid ID No. without special characters."
echo "Please try again"
else
echo "Thank you" $TITTLE $SURNAME
break
fi
done
答え1
あなたのスクリプト終了タイトルまたは姓に無効な入力が与えられるとすぐに、ループは役に立たなくなります。continue
反復をやり直すために使用します。
ただし、無効な ID を入力したという理由だけで、ユーザーに肩書きと姓を再度入力させるのは望ましくありません。そのため、1 つの大きなループではなく、ユーザーから読み取った内容ごとに 1 つのループ、合計 3 つの入力ループが必要になります。
あなたのコードは不必要に繰り返しが多く、3つのループとして書き直すとまた不必要に繰り返しになります。別の入力機能があった方が便利です。
次のスクリプトでは、それを実行しました。入力関数は、get_input
「ラベル」(ユーザーが入力する内容の説明) と、入力内の各文字が一致する必要があるパターンを受け取ります。関数はget_input
有効な文字列を標準出力に出力します。これが、スクリプトのメイン部分のコマンド置換内でこの関数を呼び出す理由です。
また、文字列検証を独自の関数に移動しました。これは、get_input
関数をよりわかりやすくし、検証ロジックを入力ロジックから分離するためです。
検証では、使用するのと同じアプローチが使用されます。つまり、有効な文字をすべて文字列から削除し、文字が残っているかどうかをテストします。残っている場合、文字列は検証に失敗します。
#!/bin/bash
# Succeeds if the first argument is non-empty and only
# consists of characters matching the pattern in the
# second argument.
is_valid () {
local string pattern
string=$1
pattern=$2
[ -n "$string" ] && [ -z "${string//$pattern}" ]
}
# Asks user for input until the given string is valid.
# The first argument is a text string describing what
# the user should enter, and the second argument is a
# pattern that all characters in the inputted data much
# match to be valid.
get_input () {
local label pattern
local string
label=$1
pattern=$2
while true; do
read -r -p "Please enter $label: " string
if is_valid "$string" "$pattern"; then
break
fi
# Complain on the standard error stream.
printf 'Invalid input, try again\n' >&2
done
printf '%s\n' "$string"
}
# Get data from user.
title=$( get_input 'your title' '[[:alpha:] ]' ) # title: only letters and spaces
surname=$( get_input 'your surname' '[[:alpha:] ]' ) # surname: same as title
id=$( get_input 'your ID no.' '[[:digit:]]' ) # ID: only digits
# Print what we got.
printf 'Title = "%s"\n' "$title"
printf 'Surname = "%s"\n' "$surname"
printf 'ID = "%s"\n' "$id"
タイトルや姓にドットなどを許可するには、パターンを から に変更します[[:alpha:] ]
。または、さらに制限を緩めて を使用して、数字以外の文字 (句読点などを含む) を許可すること[[:alpha:]. ]
もできます。[![:digit:]]
スクリプトを実行しているユーザーと同じ名前のファイルに出力を保存するには、スクリプト自体の出力をリダイレクトします。
$ ./script.sh >"$USER.txt"
これにより、スクリプトが実行され、出力が というファイルにリダイレクトされます$USER.txt
。ここで、 は$USER
現在のユーザーのユーザー名です (この変数と は$LOGNAME
通常、シェルやシステムによって既に設定されています)。
スクリプト内で最後の3printf
行を次のように変更することで、これを実行することもできます。
# Print what we got.
{
printf 'Title = "%s"\n' "$title"
printf 'Surname = "%s"\n' "$surname"
printf 'ID = "%s"\n' "$id"
} >"$USER.txt"
または、スクリプト内でユーザーから読み取った「姓」を使用する場合は、次のようにします。
# Print what we got.
{
printf 'Title = "%s"\n' "$title"
printf 'Surname = "%s"\n' "$surname"
printf 'ID = "%s"\n' "$id"
} >"$surname.txt"
にまた端末に印刷するには、次を使用しますtee
:
# Print what we got.
{
printf 'Title = "%s"\n' "$title"
printf 'Surname = "%s"\n' "$surname"
printf 'ID = "%s"\n' "$id"
} | tee "$surname.txt"
ユーザーが入力した内容を使用すると、スクリプトのユーザーが現在のディレクトリ内の任意のファイルを上書きできる可能性があることに注意してください (権限で許可されている場合)。