bash:阅读:如何捕获“\n”(换行符)字符?

bash:阅读:如何捕获“\n”(换行符)字符?

我可以用来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'
$ 

我希望同样的方法能够捕获^Dor \004

如果read做不到,有什么办法解决?

答案1

要读取 1 个字符,请-N改为使用,它始终读取一个字符并且不进行$IFS处理:

read -rN1 var

read -rn1读取一条记录最多一个字符并仍然进行$IFS处理(换行符是默认值,$IFS这解释了为什么即使您读取 NUL 分隔的记录也会得到空结果)。您可以使用它来限制您读取的记录的长度。

在您的情况下,使用 NUL 分隔的记录(使用-d ''),其工作方式与无论如何都无法在其变量中存储 NUL 字符IFS= read -d '' -rn1 var相同,因此将保留为空并返回非零退出状态。bashprintf '\0' | read -rN1 var$var

为了能够读取包括 NUL 在内的任意字符,您可以使用 shell,zsh而不是使用以下语法:

read -k1 'var?Enter a character: '

(不需要-rIFS=那里。但是请注意,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,您将无法区分空格、制表符和换行符。

相关内容