Вот что у меня есть. Я пытаюсь проверить 3 ввода. Первый и второй вводы не просят меня ввести правильный ввод. Что не так?
#!/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
для повторного выполнения итерации.
Однако вы не хотите заставлять пользователя снова вводить свое имя и фамилию только потому, что он ввел неверный идентификатор, поэтому вам понадобятся три цикла ввода вместо одного большого цикла: по одному циклу на каждую информацию, которую вы считываете с пользователя.
Ваш код без необходимости повторяется, и переписывание его в виде трех циклов приведет ктакжебыть без необходимости повторяющимися. Было бы удобнее иметь отдельную функцию ввода.
В следующем скрипте я это сделал. Функция ввода 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
, обычно уже заданы оболочкой и/или системой).
Вы также можете сделать это в самом скрипте, изменив последние три printf
строки на
# 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"
Обратите внимание, что использование введенных пользователем данных потенциально позволяет пользователю скрипта перезаписывать произвольные файлы в текущем каталоге (при условии, что разрешения это позволяют).