【发布时间】:2014-06-06 07:44:25
【问题描述】:
我有一台带有最小定制 linux 内核的旧设备。大约 20 年前,我们从一家公司购买了该设备,并对其进行了编程以满足我们的需求。
uname -r
2.4.21
我在设备上开发了一个基于文本的 UI,并允许通过 telnet 和串行端口访问它。
使用 telnet 连接时,两次调用 read -s STR 会导致第二次读取被忽略。这是因为 telnet 以"\r\n" 结束行。
例如:
echo "Enter new password: "; read -s password1
echo "Enter new password again: "; read -s password2 #<--this read returns directly
所以我的解决方案是在每次读取调用后从标准输入读取所有字符。
但是,仅使用串行通信将"\n" 作为行尾发送。所以我决定在上面的读取调用中增加 1 秒的超时时间。
所以,我基本上是这样结束的:
echo "Enter new password: "; read -s password1
read -t 1 -n 1000 ignore
echo "Enter new password again: "; read -s password2
read -t 1 -n 1000 ignore
令我惊讶的是,read -t 1 有时会阻塞。所以我运行了以下内容来说明这种行为:
set -x
while true;
do
read -t 1 -n 10000 STR
echo "timeout"
sleep 5
done
脚本在 2 次循环后挂起,只有在我按 enter 时才会继续。
最后我尝试了以下方法:
set -x
unset STR
while true;
do
read -s -n 1 char
if [[ $char == $'\r' ]]
then
read -s -n 1 ignore
break
elif [[ $char == $'\n' ]]
then
break
fi
STR=$STR$char
done
这导致:
++ true
++ read -s -n 1 char
]][[ a == \
++ [[ a == \
]]
++ STR=a
++ true
++ read -s -n 1 char <-------- HERE I PRESSED ENTER
]][[ '' == \
++ [[ '' == \
]]
++ STR=a
++ true
++ read -s -n 1 char
所以ENTER 或"\n" 被转换为'',因此它不会跳出循环。
在较新的设备上,我们可以更好地控制内核
uname -r
2.6.24.6
该问题不会发生,即调用 read 两次不会导致第二次 read 调用被忽略。
有没有人想办法解决这个问题?
【问题讨论】:
-
这听起来有些不对劲。首先,由于该对是
\r\n,因此第一次读取应该在存储在参数中的字符串末尾包含\r,而不是需要第二次读取来清除它。其次,虽然 telnet 协议可能使用\r\n,但不应将它们传递给通过 telnet 接收其输入的底层 shell。 -
@chepner 确实很奇怪。在我看来,
\r包含在内部字段分隔符 (IFS) 中。但是,由于内核中缺乏对基本系统命令的支持,我无法打印IFS。我试过export IFS=' \t\n',但无济于事。顺便说一句,除了[[ $char == $'\r' ]] || [[ $char == $'\n' ]],还有其他方法可以测试\r或\n吗?或者甚至打印以十六进制接收的字符? -
我认为内核版本根本不重要。你能告诉我们你正在使用的 shell 和它的版本吗?
-
@mkalkov GNU bash,版本 2.05.8(1)-release (i386-redhat-linux-gnu)