bash读取超时仅适用于用户输入的第一个字符

bash读取超时仅适用于用户输入的第一个字符,bash,timeout,user-input,Bash,Timeout,User Input,我搜索了一个简单的解决方案,该解决方案将读取具有以下功能的用户输入: 如果根本没有用户输入,则10秒后超时 如果在前10秒内键入第一个字符,则用户有无限的时间完成其答案 我已经找到了一个类似的解决方案(在每个输入字符后超时)。尽管如此,这并不是我一直在寻找的功能,因此我开发了一个双线解决方案,如下所示: read -N 1 -t 10 -p "What is your name? > " a [ "$a" != "" ] && read b && ech

我搜索了一个简单的解决方案,该解决方案将读取具有以下功能的用户输入:

  • 如果根本没有用户输入,则10秒后超时
  • 如果在前10秒内键入第一个字符,则用户有无限的时间完成其答案
我已经找到了一个类似的解决方案(在每个输入字符后超时)。尽管如此,这并不是我一直在寻找的功能,因此我开发了一个双线解决方案,如下所示:

read -N 1 -t 10 -p "What is your name? > " a
[ "$a" != "" ] && read b && echo "Your name is $a$b" || echo "(timeout)"
read -N 1 -t 10 -s -p "What is your name? > " a || echo "(timeout)" \
  && [ -n "$a" ] && read -ei "$a" b || echo \
  && echo "Your name is \"$b\""
如果用户在输入第一个字符前等待10秒,输出将为:

What is your name? > (timeout)
如果用户在10秒内键入第一个字符,则他有无限时间完成此任务。输出如下所示:

What is your name? > Oliver
Your name is Oliver

if read -N 1 -t 10 -s -p "What is your name? " FIRST_CHARACTER; then
  if [ -n "$FIRST_CHARACTER" ]; then
    read -ei "$FIRST_CHARACTER" FULL_NAME
  else
    echo
  fi
  echo "Your name is \"$FULL_NAME\""
else
  echo "(timeout)"
fi
但是,有以下警告:第一个字符在键入后不可编辑,而所有其他字符都可以编辑(退格和重新键入)


您对解决警告有什么想法吗?或者您对请求的行为有其他简单的解决方案吗?

启用
readline
并添加
$a
作为第二次读取的默认值

# read one letter, but don't show it
read -s -N 1 -t 10 -p "What is your name? > " a

if [ -n "$a" ]; then
  # Now supply the first letter and let the user type
  # the rest at their leisure.
  read -ei "$a" b && echo "Your name is $b"
else
  echo "(timeout)"
fi
这仍然会在第一个字母被回答后显示第二个提示,但我认为没有更好的方法来处理这个问题;无法“取消”读取
的超时。理想的解决方案是使用一些命令而不是
读取
,但是您必须自己编写(可能是作为可加载的内置程序,在C中)。

此解决方案可以

read -n1 -t 10 -p "Enter Name : " name && echo -en "\r" &&
read -e -i "$name" -p "Enter Name : " name || echo "(timeout)"
注意:第二个
读取
使用从第一个(
-i
选项)捕获的文本提供可编辑的缓冲区。回车和相同的提示给用户一种印象,即他正在输入相同的值。

测试条件: GNUBash,版本4.4.19(1)-发布 Ubuntu 18.04.2 LTS

我创建了一个函数来解决第一个字母不可编辑的警告,如下所示。我只在本地linux服务器上进行了测试,我不认为这会在其他地方或新/旧版本的BASH上起作用(或者阅读了相关内容,但我无法说出我正在运行的版本)

您可以调用此函数,如下所示:

declare n=""
__readInput
if [[ $? -eq 0 ]] || [[ ${#n} -eq 0 ]] ;then
    echo "Your name is $n"
else
    echo "I'm sorry, I didn't quite catch your name!"
fi
上述说明的注意事项 所以,你有一个我修正的警告,也许你(或我们的朋友)可以修正这个。任何未包含在
$rg
REGEX变量中的输入字符都将被视为退格。这意味着您的用户可以点击
F7
=
\
,或者除
$rg
中指定的字符以外的任何字符,并且将被视为退格

简短回答: 在第一个读取命令上添加
-s
选项,在第二个读取命令上添加
-ei
选项:

read -s -N 1 -t 10 -p "What is your name? > " a
[ "$a" != "" ] && read -ei "$a" b && echo "Your name is $b" || echo "(timeout)"
或者更好地处理空输入:

read -s -N 1 -t 10 -p "What is your name? > " a || echo "(timeout)" \
  && [ -n "$a" ] && read -ei "$a" b || echo \
  && echo "Your name is \"$b\""
详细回答: 在@chepner的回答(感谢
-ei
选项!)和@paul hodges的评论的帮助下,我找到了一篇推广
-s
阅读选项的文章,我能够创建一个与我最初的2行程序非常相似的工作解决方案:

read -N 1 -t 10 -s -p "What is your name? > " a
[ "$a" != "" ] && read -ei "$a" b && echo "Your name is $b" || echo "(timeout)"
你们中的一些人可能想要相同功能的更精细版本:

if read -N 1 -t 10 -s -p "What is your name? " FIRST_CHARACTER; then
  read -ei "$FIRST_CHARACTER" FULL_NAME
  echo "Your name is $FULL_NAME"
else
  echo "(timeout)"
fi
说明:

  • 第一次读取命令中的
    -s
    选项将确保键入时不会打印出第一个字符
  • -n1
    -n1
    选项将确保仅将第一个字符读入第一个字符变量
  • -ei
    选项将把
    $FIRST\u CHARACTER
    读入全名,然后用户继续将字符2写入n
  • 用户可以重新考虑他的答案,并且可以删除整个输入,包括带有退格的第一个字符
我已经对它进行了测试,这些选项的组合似乎达到了目的

解决带有空输入的警告 但是,还有一个小警告:如果用户只是键入
:第二个读取命令将等待输入,直到用户再次按下
。这可以通过如下方式进行修复:

What is your name? > Oliver
Your name is Oliver

if read -N 1 -t 10 -s -p "What is your name? " FIRST_CHARACTER; then
  if [ -n "$FIRST_CHARACTER" ]; then
    read -ei "$FIRST_CHARACTER" FULL_NAME
  else
    echo
  fi
  echo "Your name is \"$FULL_NAME\""
else
  echo "(timeout)"
fi
在两个班轮的样式中,我们将得到三个班轮,如下所示:

read -N 1 -t 10 -p "What is your name? > " a
[ "$a" != "" ] && read b && echo "Your name is $a$b" || echo "(timeout)"
read -N 1 -t 10 -s -p "What is your name? > " a || echo "(timeout)" \
  && [ -n "$a" ] && read -ei "$a" b || echo \
  && echo "Your name is \"$b\""
试验 两个版本(嵌套if版本和三行程序)的代码的行为如下:

read -N 1 -t 10 -p "What is your name? > " a
[ "$a" != "" ] && read b && echo "Your name is $a$b" || echo "(timeout)"
read -N 1 -t 10 -s -p "What is your name? > " a || echo "(timeout)" \
  && [ -n "$a" ] && read -ei "$a" b || echo \
  && echo "Your name is \"$b\""
  • 如果用户在10秒内没有做任何事情,输出将产生
  • 如果用户写入
    Oliver
    ,则输出将为
  • 如果用户开始写“Oliver”,然后认为他想被称为“Michael”,他可以使用退格键完全删除“Oliver”,并相应地替换它。输出将是:
在输入名字“奥利弗”后。然后,按backspace键6次或以上后:

What is your name?
在输入Michael之后:


希望这能有所帮助。

我很确定所有这些问题都可以解决,但处理每一个问题,尤其是所有问题的代码并不重要。您可能会在中找到一些有用的提示。可以通过在第一个读取命令上添加
-s
选项和在第二个读取命令上添加
-ei
选项来解决问题。更多信息见下文的答案,更详细的答案见下文。感谢您的链接,它将我们引导到
-s
选项。因此,我已将您的评论标记为有用。我测试了您的解决方案,出现了一个奇怪的效果:第一个字符加倍。警告仍然存在,即第一个加倍字符无法删除。例如,我键入“Oliver”,然后我将看到“OOliver”。我使用了10次backspace,但是第一个O不能被删除。如果我接着键入“Michael”,我会得到“OMichael”。答案对我仍然很有帮助,因为我已经了解了有用的
-ei
阅读选项。因此,我会按相应的三角形。哦,对不起<代码>