如何在shell脚本中只读取一个字符

51

我希望有一个类似于C语言中getche()的选项。如何从命令行读取单个字符输入?

我们可以使用read命令来实现吗?

5个回答

73

在bash中,read可以实现:

read -n1 ans

13
请键入以下命令并按回车以运行程序:read -p "请输入任何字符:" -n1 ans; echo -e "\n您输入的是:$ans"。该程序将提示用户输入一个字符,并在用户输入后显示所输入的字符。 - dimir
并非所有的shell都以相同的方式实现内建命令。对于Z-Shell来说,read -k1 ans"?输入任意字符:" ; echo -e "\n你输入的是:$ans"应该与bash中dimir的评论具有相同的效果。 - Friartek

40

read -n1适用于bash。

stty raw模式会阻止ctrl-c的使用并可能使您陷入输入循环中无法退出。此外,man页面上说stty -raw不能保证将终端返回到相同的状态。

因此,在dtmilano的答案基础上,使用stty -icanon -echo可以避免这些问题。

#/bin/ksh
## /bin/{ksh,sh,zsh,...}

# read_char var
read_char() {
  stty -icanon -echo
  eval "$1=\$(dd bs=1 count=1 2>/dev/null)"
  stty icanon echo
}

read_char char
echo "got $char"

2
这也适用于ash(在“BusyBox v1.10.2”上进行了测试),以及在debian上dash为“#!/bin/sh”。 - Sam
嗨"fess ."。我认为我的职责是告知您关于这个问题这个元问题。我完全打算遵守我的承诺(也许不是在我获得75分之后,那会使我降到25分,然后我可能会失去“随处评论”,但是一旦我达到100分,我将使用奖励系统)。 - Sam
1
@Sam 我建议你现在保留你的声望,因为你将需要这个声望来完成各种事情:https://stackoverflow.com/help/privileges。我提供悬赏,所以不用担心。 - Cœur
这在输入\n上失败了。修复方法是:eval "$1=\$'\\x$(dd bs=1 count=1 2>/dev/null | xxd -p)'" - undefined
stty icanon echo破坏了read的行编辑功能。修复方法:使用stty sane - undefined
显示剩余2条评论

16

在ksh中,您基本上可以执行:

stty raw
REPLY=$(dd bs=1 count=1 2> /dev/null)
stty -raw

9

1
有些人认为“从命令行输入”是指将参数传递给命令,而不是从STDIN读取...所以请不要攻击我。但是,我也有一个(可能不是最复杂的)STDIN解决方案!当使用bash并且将数据存储在变量中时,可以使用参数扩展。
${parameter:offset:length}

我可以帮助你在给定的参数 ($1, $2, $3 等) 上执行操作。

脚本

#!/usr/bin/env bash

testdata1="1234"
testdata2="abcd"

echo ${testdata1:0:1}
echo ${testdata2:0:1}
echo ${1:0:1} # argument #1 from command line

执行
$ ./test.sh foo
1
a
f

从标准输入读取

脚本

#!/usr/bin/env bash

echo please type in your message:
read message
echo 1st char: ${message:0:1}

执行
$ ./test.sh 
please type in your message:
Foo
1st char: F

1
读取单个字符更多地涉及有条件地读取、等待或在字符到达时执行工作,而不是假设您已经成功地预读了单个字符。这个过程会无限期地阻塞,无论是否有char 1,交替消耗它所能够的一切并等待更多内容,直到它消耗某个分隔符。它会丢弃分隔符,这可能是换行符、EOF或您正在尝试读取的第一个字符(在这种情况下长度为0)。在某些情况下有效,但是...买家需谨慎。 - John P

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接