有没有一种方法可以要求在达到字符限制后使用read-n按下回车键,而不是自动跳到脚本中的下一行?
例如,在以下脚本中:
echo "Please enter your credentials below"
read -p "Please enter your username: " -e -n 15 usern
read -p "Please enter your password: " -s -e -n 15 passw
一旦为用户名输入了15个字符,它就会自动跳转到密码提示。然而,一旦达到15个字符(除了退格键和回车键(,就可以简单地停止允许输入,并要求用户按回车键继续输入密码,这将更方便用户。这就是大多数登录的工作方式,毕竟。。。
我知道我可以使用while循环/if语句来限制usern变量中的字符限制(例如使用-gt(,但我想知道如何具体限制用户按退格键或回车键(如果他们想编辑用户名中的单个字符,甚至可以按箭头键,但我现在不担心(,一旦达到这15个字符,并REQUIRE(要求(用户按enter键继续进行以下提示。
希望我的要求是合理的。提前感谢大家!
如注释中所述,bash的read
无法重现特定键的预期行为。但是,您可以通过滚动自己的输入解析来避免使用read
。
需要考虑的几点:
- 终端行设置需要使用
stty
进行调整,以避免在键入时打印输入字符(即我们只想打印消息,否则字符会重复( - 终端模拟器需要支持
VT100
转义码,以便在重新绘制提示时擦除行并移动光标 - 字符可以通过ascii代码进行比较,但当按下回车键时,我们不会得到换行符本身的读取字符。但是,由于读取了其他空白字符,所以这不是问题
以下脚本通过接受不超过给定限制的字符(对于密码,不打印键入的字符(来实现预期行为。只有在按下回车键时才会提交输入。
#!/bin/sh
set -eu
parse() {
message=$1
var=$2
is_password=$3
input=
stty -icanon -echo
while true; do
# Clear line, move cursor to beginning, then print prompt
if [ "$is_password" -eq 1 ]; then
printf '33[2Kr'"$message "
else
printf '33[2Kr'"$message $input"
fi
# Read 1 character
i=$(dd bs=1 count=1 2>/dev/null)
# Was a backspace read?
if echo "$i" | grep -qP 'x7f'; then
# Remove last character
input=$(echo "$input" | sed 's/.$//')
# Only add read character if input field limit wasn't reached
elif [ ${#input} -lt 15 ]; then
input=$input$i
fi
# Was a newline read?
if [ -z "$i" ]; then
break
fi
done
stty icanon echo
eval "$var=$input"
}
echo "Please enter your credentials below"
parse "Please enter your username:" "usern" 0
printf "n%sn" "Read username: $usern"
parse "Please enter your password:" "userp" 1
printf "n%sn" "Read password: $userp"