我可以用来read
捕获\n
\012
或 换行符吗?
定义测试函数:
f() { read -rd '' -n1 -p "Enter a character: " char &&
printf "\nYou entered: %q\n" "$char"; }
运行该函数,按Enter:
$ f;
Enter a character:
You entered: ''
嗯。这是一个空字符串。
我如何获得预期的输出:
$ f;
Enter a character:
You entered: $'\012'
$
我希望同样的方法能够捕获^D
or \004
。
如果read
做不到,有什么办法解决?
答案1
要读取 1 个字符,请-N
改为使用,它始终读取一个字符并且不进行$IFS
处理:
read -rN1 var
read -rn1
读取一条记录最多一个字符并仍然进行$IFS
处理(换行符是默认值,$IFS
这解释了为什么即使您读取 NUL 分隔的记录也会得到空结果)。您可以使用它来限制您读取的记录的长度。
在您的情况下,使用 NUL 分隔的记录(使用-d ''
),其工作方式与无论如何都无法在其变量中存储 NUL 字符IFS= read -d '' -rn1 var
相同,因此将保留为空并返回非零退出状态。bash
printf '\0' | read -rN1 var
$var
为了能够读取包括 NUL 在内的任意字符,您可以使用 shell,zsh
而不是使用以下语法:
read -k1 'var?Enter a character: '
(不需要-r
或IFS=
那里。但是请注意,read -k
读取从航站楼(k
是为了钥匙; zsh 的-k
选项比 bash 甚至 ksh93-N
早几十年)。要从标准输入读取,请使用read -u0 -k1
)。
示例(此处按Ctrl+Space输入 NUL 字符):
$ read -k1 'var?Enter a character: '
Enter a character: ^@
$ printf '%q\n' $var
$'\0'
请注意,要能够读取特点,read
可能需要读取多个字节。如果输入以多字节字符的第一个字节开始,它将至少再读取一个字节,因此$var
如果输入包含未形成有效的字节序列,则最终可能会包含 shell 认为长度大于 1 的内容人物。
例如在 UTF-8 语言环境中:
$ printf '\xfc\x80\x80\x80\x80XYZ' | bash -c 'read -rN1 a; printf "<%q>\n" "$a" "${#a}"; wc -c'
<$'\374\200\200\200\200X'>
<6>
2
$ printf '\xfc\x80\x80\x80\x80XYZ' | zsh -c 'read -u0 -k1 a; printf "<%q>\n" $a $#a; wc -c'
<$'\374'$'\200'$'\200'$'\200'$'\200'X>
<6>
2
在 UTF-8 中,0xFC 是 6 字节长字符的第一个字节,其他 5 个字节意味着设置了第 8 位且未设置第 7 位,但是我们只提供了 4 个。read
仍然读取额外的内容X
以尝试找到字符的末尾$var
,与不形成有效字符的 5 个字节一起结束,最终每个字节都被计为一个字符。
答案2
bash
内置read
可以做到这一点:
read -rd $'\0' -p ... -n 1
printf '\nYou typed ASCII %02x\n' "'$REPLY"
(这段代码不适用于多字节字符)
请注意,我没有像您那样将读取的内容放入变量中char
。这是因为这样做会从 中删除 IFS 中的字符char
。使用标准 IFS,您将无法区分空格、制表符和换行符。