Bash:屏蔽用户输入的密码,支持退格和特殊字符
Bash: Masking user input for a password, with * support for backspace and special characters
我根据 @SiegeX and @mklement0 from this question.
屏蔽密码输入的想法在下面制作了这个片段
太棒了,我唯一想要的添加是只删除输入字符的长度,所以我们不会删除整行。
我不是很了解这个,所以 运行 遇到了错误。
在下面,输入“12345”并退格,数字不会“退格”;没有错误。
输入“123FourFive”并退格,产生错误:line 9: [[: 123FourFiv: value too great for base (error token is "123FourFiv")
输入“OneTwo345”并退格,似乎工作正常。
输入密码中可能期望的符号然后退格会产生错误:line 9: [[: OneTwo./?: syntax error: invalid arithmetic operator (error token is "./?")
在输入过程中按箭头键也会在退格后产生乱码...
如何改进这一点,以便我们屏蔽用户输入,只删除已输入的内容?
还是我们在“重新发明轮子”?还有其他东西可以做我已经尝试做的事情吗(这是屏蔽用户输入以在 bash 脚本中获取密码以将其放入变量中)?
用户环境是 Linux Mint 19.3 with Cinnamon。
#!/bin/bash
printf "\n\tPlease enter password: "
# mask the input for the password by @SiegeX and @mklement0 (
while IFS= read -r -s -n1 char; do
[[ -z "${char}" ]] && { printf '\n'; break; } # ENTER pressed; output \n and break.
if [[ "${char}" == $'\x7f' ]]; then # backspace was pressed
# @nooblag, only delete for length of entered chars?
if [[ "${password}" -lt "${#password}" ]]; then printf '\b \b'; fi # erase one '*' to the left.
[[ -n $password ]] && password=${password%?} # remove last char from output variable
else
# add typed char to output variable
password+="${char}"
# print '*' in its stead
printf '*'
fi
done
printf "\tPassword: ${password}\n\n"
更新: askpass
按照建议 here 几乎可以满足我的要求,但是如果用户尝试 abort/kill Ctrl+C 它弄乱了终端...
这可能是解决方案!摘自 here.
#!/bin/bash
#
# Read and echo a password, echoing responsive 'stars' for input characters
# Also handles: backspaces, deleted and ^U (kill-line) control-chars
#
unset PWORD
PWORD=
echo -n 'password: ' 1>&2
while true; do
IFS= read -r -N1 -s char
# Note a NULL will return a empty string
# Convert users key press to hexadecimal character code
code=$(printf '%02x' "'$char") # EOL (empty char) -> 00
case "$code" in
''|0a|0d) break ;; # Exit EOF, Linefeed or Return
08|7f) # backspace or delete
if [ -n "$PWORD" ]; then
PWORD="$( echo "$PWORD" | sed 's/.$//' )"
echo -n $'\b \b' 1>&2
fi
;;
15) # ^U or kill line
echo -n "$PWORD" | sed 's/./\cH \cH/g' >&2
PWORD=''
;;
[01]?) ;; # Ignore ALL other control characters
*) PWORD="$PWORD$char"
echo -n '*' 1>&2
;;
esac
done
echo
echo $PWORD
我根据 @SiegeX and @mklement0 from this question.
屏蔽密码输入的想法在下面制作了这个片段太棒了,我唯一想要的添加是只删除输入字符的长度,所以我们不会删除整行。
我不是很了解这个,所以 运行 遇到了错误。
在下面,输入“12345”并退格,数字不会“退格”;没有错误。
输入“123FourFive”并退格,产生错误:line 9: [[: 123FourFiv: value too great for base (error token is "123FourFiv")
输入“OneTwo345”并退格,似乎工作正常。
输入密码中可能期望的符号然后退格会产生错误:line 9: [[: OneTwo./?: syntax error: invalid arithmetic operator (error token is "./?")
在输入过程中按箭头键也会在退格后产生乱码...
如何改进这一点,以便我们屏蔽用户输入,只删除已输入的内容?
还是我们在“重新发明轮子”?还有其他东西可以做我已经尝试做的事情吗(这是屏蔽用户输入以在 bash 脚本中获取密码以将其放入变量中)?
用户环境是 Linux Mint 19.3 with Cinnamon。
#!/bin/bash
printf "\n\tPlease enter password: "
# mask the input for the password by @SiegeX and @mklement0 (
while IFS= read -r -s -n1 char; do
[[ -z "${char}" ]] && { printf '\n'; break; } # ENTER pressed; output \n and break.
if [[ "${char}" == $'\x7f' ]]; then # backspace was pressed
# @nooblag, only delete for length of entered chars?
if [[ "${password}" -lt "${#password}" ]]; then printf '\b \b'; fi # erase one '*' to the left.
[[ -n $password ]] && password=${password%?} # remove last char from output variable
else
# add typed char to output variable
password+="${char}"
# print '*' in its stead
printf '*'
fi
done
printf "\tPassword: ${password}\n\n"
更新: askpass
按照建议 here 几乎可以满足我的要求,但是如果用户尝试 abort/kill Ctrl+C 它弄乱了终端...
这可能是解决方案!摘自 here.
#!/bin/bash
#
# Read and echo a password, echoing responsive 'stars' for input characters
# Also handles: backspaces, deleted and ^U (kill-line) control-chars
#
unset PWORD
PWORD=
echo -n 'password: ' 1>&2
while true; do
IFS= read -r -N1 -s char
# Note a NULL will return a empty string
# Convert users key press to hexadecimal character code
code=$(printf '%02x' "'$char") # EOL (empty char) -> 00
case "$code" in
''|0a|0d) break ;; # Exit EOF, Linefeed or Return
08|7f) # backspace or delete
if [ -n "$PWORD" ]; then
PWORD="$( echo "$PWORD" | sed 's/.$//' )"
echo -n $'\b \b' 1>&2
fi
;;
15) # ^U or kill line
echo -n "$PWORD" | sed 's/./\cH \cH/g' >&2
PWORD=''
;;
[01]?) ;; # Ignore ALL other control characters
*) PWORD="$PWORD$char"
echo -n '*' 1>&2
;;
esac
done
echo
echo $PWORD