![](/img/trans.png)
[英]Bash discards command line arguments when passing to another bash shell
[英]bash: read discards terminal line input after 4096 bytes
要演示此问题,请在Linux中运行此命令后粘贴长字符串(> 4096字节):
read foo && wc -c <<<"$foo"
结果是4096,这意味着输入被截断。
一些研究显示终端线缓冲区大小硬编码为4096,这解释了截断。 但是,当我尝试使用-n
选项读取时,它有效:
read -n 32768 foo && wc -c <<<"$foo"
结果是输入的实际长度(+1,但这是由于here-string)而不是4096。
所以我想知道选项-n 32768
的魔力是什么。 我没有在bash手册页中找到关于此的相关信息。 这是我们可以依赖的功能吗?
bash的执行read
允许您指定的字符的最大数量的阅读,使用-n
标志,或替代终止符,使用-d
标志。 这些选项都不适用于标准终端输入,因为通常终端驱动程序将输入保持在其自己的内部缓冲区中,直到用户键入ENTER键(或某些其他键击,如Control-C或Control-D)。
例如, read -n1 char
后面的想法是,您希望在用户键入单个字符后立即返回read
,而不是您希望read
等待用户键入完整行然后返回第一个字符那条线的特征。 同样,命令read -d';' command
一旦用户键入分号, read -d';' command
应该返回; 再次,等待用户键入一个完整的行,然后只是将它的一部分返回到分号将是意外的。
因此,为了使这些选项按预期工作, read
builtin需要告诉终端驱动程序在键入后立即返回字符。 如果输入设备是终端,并且您指定了最大输入长度或除换行符之外的分隔符,则read
通过修改以下termios标志将终端置于“原始”模式:
off: ICANON INLCR OCRNL ONOCR ONLRET
on: ISIG IEXTEN ICRNL OPOST ONLCR
关闭ICANON
后,终端驱动程序不再缓冲输入。
正如原帖中所述,Linux内核驱动程序使用固定长度的4096输入缓冲区来实现行编辑,它将简单地忽略不适合此缓冲区的类型字符。 因此,当终端处于正常输入模式时,您的输入将在4096个字符后被截断。 关闭ICANON
后,驱动程序会尽快传递字符,并且不会截断输入。
但是关闭输入规范化的副作用是终端驱动程序不再解释退格键并删除键,从而无法进行行编辑。 你可以试试这个:
# I typed a, x, backspace, b, return
$ read -n 4 input
ax^?b
$ printf "%s" "$input" | hd
00000000 61 62 7f 78 |ab.x|
00000004
请注意,退格键( 0x7f
)发送的删除字符将保留在输入中。
这是一种不太理想的用户体验; 你当然不希望它输入长输入。 在大多数情况下,人们希望退格“工作”。 但是,它非常适合编写小型控制台游戏,其中脚本需要对键入的每个击键做出反应。
Bash本身使用readline
库来读取输入。 readline
还将终端置于原始模式,但与内置read
不同,它实际上处理退格字符,箭头键和大量其他字符列表,包括内核驱动程序显然一无所知的许多特殊字符,如制表符完成和历史记录搜索。
read
builtin也有-e
标志,这使得它使用readline
(如果它是从终端读取)。 使用-e
进行上述实验可能会产生更方便的结果:
# I typed a, x, backspace, b, c, d
$ read -en4 input
abcd
$ printf "%s" "$input" | hd
00000000 61 62 63 64 |abcd|
00000004
这一次, readline
处理了退格键,并在键入四个“真实”字符后返回read
。
从bash手册页上阅读:
-n nchars
read读取nchars字符后返回,而不是等待完整的输入行,但如果在分隔符之前读取的字符数少于nchars,则表示分隔符。
(我很确定这是一个特定于bash的扩展,如果使用其他shell,你不能依赖它,除非你验证特定的一个也支持它)。 编辑:例如,zsh与-n
做了一些非常不同的事情。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.