
Я пишу функцию, которая запрашивает имя файла, а затем проверяет, начинается ли ввод с символа альфа, если нет, она повторно запрашивает имя у пользователя, пока не будут выполнены критерии. Она также выдает дополнительное сообщение, если пользователь вводит путь (путь — это все, что содержит '/' для целей этого задания). Вот тут-то у меня и возникает проблема...
вот мой код...
#1) make a getname function that will prompt for filename
function getname(){
trap control_c SIGINT
local fname=$1;
#if there is no input prompt user for file name
if [ ! $1 ]; then
read -p "Enter a file name: " fname;
fi;
#until grep is given a valid file name
until ( grep -E '^[a-zA-Z_]\w+$' <<< "$fname" > /dev/null 2>&1); do
#this is were the error is
if echo "$fname" | grep -E '/';
then #this tests if fname is a file directory
echo "Paths are not a legal file name.";
fi;
read -p "Enter a legal file name: " fname;
done
echo "$fname"
}
Оператор if в цикле until ни при каких обстоятельствах не будет сообщать пользователю, что пути не являются допустимым вводом, а также не выдаст никаких ошибок. Как бы мне правильно реализовать grep в операторе if?
решение1
На самом деле у меня это работает в Fedora 26 с использованием GNU bash, version 4.4.12(1)-release (x86_64-redhat-linux-gnu)
. Функция продолжает спрашивать, указан ли путь. Смотрите вывод.
[@host testing]$ getname
Enter a file name: ab/sav
ab/sav
Paths are not a legal file name.
Enter a legal file name: abc
abc
[@host testing]$
Однако я обнаружил две небольшие проблемы. Во-первых, он печатает путь, а затем снова запрашивает ввод. Это можно решить, используя switch grep -q
(q для quiet) в if
операторе (также работает для until
, тогда перенаправление вывода больше не нужно). Во-вторых, один символ всегда недопустим в until
цикле. Это можно решить, изменив \w+
в regex для \w*
.
решение2
grep
в операторе until очень громоздкий, вы можете упростить его.
Могу предложить такой метод:
until [ ! -z "$fname" ]; do
read -p "Enter a legal file name: " fname
grep -E '^[a-zA-Z_]\w+$' <<< "$fname" > /dev/null 2>&1
#check exit code
if [ $? -ne 0 ]; then
echo "Paths are not a legal file name."
fname=""
fi
done
При необходимости добавьте любые другие условия внутрь цикла until.
Если вы хотите обрабатывать сообщения для пользователей, то вы можете использовать этот прием без нескольких read
появлений команд:
fname=""
message_for_user="Enter a file name: "
until [ ! -z "$fname" ]; do
read -p "$message_for_user" fname
grep -E '^[a-zA-Z_]\w+$' <<< "$fname" > /dev/null 2>&1
#check exit code
if [ $? -ne 0 ]; then
echo "Paths are not a legal file name."
fname=""
message_for_user="Enter a legal file name: "
fi
done
Вывод будет следующим:
Enter a file name: 1laha
Paths are not a legal file name.
Enter a legal file name:
Обратите внимание, что первая и третья строки отличаются.
решение3
Вы можете использовать регулярное выражение if
непосредственно в выражении:
if [[ $name =~ ^[a-zA-Z] ]]
или:
if [[ $name =~ ^[:alpha:] ]]