如何在Bash中逐字符过滤密码输入、抑制ESC序列并限制首字符
实现带过滤规则的逐字符密码输入(无read -e)
要实现符合要求的密码输入逻辑,需要在逐字符读取的基础上,加入首字符校验、特殊字符过滤、ESC序列识别和退格处理,以下是完整实现:
#!/bin/bash # 定义允许的字符集合 allowedDefaultChars='[a-zA-Z0-9]' allowedSpecialChars='[-_ \(\)/~?!§,.\#+]' pw="" while true; do # 逐字符读取,-r不转义,-s不回显,-n1只读一个字符 read -rsn 1 input_char # 处理空输入(比如某些终端的特殊情况) [[ -z "$input_char" ]] && continue # 处理ESC序列(方向键、功能键等以ESC开头的非打印序列) if [[ "$input_char" == $'\e' ]]; then # 读取ESC后的后续字符,直接丢弃整个序列 read -rsn 2 -t 0.1 continue fi # 处理退格键(ASCII 127或^H) if [[ "$input_char" == $'\x7f' || "$input_char" == $'\x08' ]]; then # 密码不为空时才删除最后一个字符 if [[ -n "$pw" ]]; then pw="${pw%?}" # 输出退格+空格+退格,实现视觉上的删除效果 printf '\b \b' fi continue fi # 处理回车键(结束输入) if [[ "$input_char" == $'\n' || "$input_char" == $'\r' ]]; then # 确保密码非空才退出循环 [[ -n "$pw" ]] && break continue fi # 首字符校验:只能是字母或数字 if [[ -z "$pw" ]]; then if [[ "$input_char" =~ $allowedDefaultChars ]]; then pw+="$input_char" printf '*' # 输出星号作为输入反馈 fi else # 后续字符允许字母数字+指定特殊字符 if [[ "$input_char" =~ $allowedDefaultChars || "$input_char" =~ $allowedSpecialChars ]]; then pw+="$input_char" printf '*' # 输出星号作为输入反馈 fi fi done # 换行,避免后续输出和密码提示符混在一起 echo echo "输入的密码为:$pw"
关键逻辑说明
- ESC序列过滤:当读取到ESC字符(
$'\e')时,立即读取后续2个字符(方向键等序列一般是ESC+2个字符)并丢弃,避免这些非打印字符污染密码。-t 0.1设置超时,防止终端无响应。 - 退格处理:识别ASCII退格(
\x7f)和Ctrl+H(\x08),删除密码的最后一个字符,同时输出\b \b实现终端上的字符删除视觉效果。 - 首字符限制:密码为空时,只接受字母或数字;密码非空后,才允许指定的特殊字符。
- 输入反馈:每输入一个合法字符,输出一个
*,让用户知道输入已被接受,同时隐藏真实密码内容。 - 结束输入:按下回车(
\n或\r)且密码非空时,退出循环完成输入。
内容的提问来源于stack exchange,提问作者fozzybear
相关产品推荐
相关产品推荐

