Linux终端输入:以4095个字符的限制从终端截断行读取用户输入
在bash脚本中,在设置Linux终端输入:以4095个字符的限制从终端截断行读取用户输入,linux,input,terminal,Linux,Input,Terminal,在bash脚本中,在设置IFS=$'\n'之后,我尝试使用内置的read命令从标准输入读取行。如果我将输入粘贴到读取,则行将被截断为4095个字符的限制。这个限制似乎来自终端的读取,因为它工作得非常好: fill= for i in $(seq 1 94); do fill="${fill}x"; done for i in $(seq 1 100); do printf "%04d00$fill" $i; done | (read line; echo $line) 我在Python脚本中体
IFS=$'\n'
之后,我尝试使用内置的read
命令从标准输入读取行。如果我将输入粘贴到读取,则行将被截断为4095个字符的限制。这个限制似乎来自终端的读取,因为它工作得非常好:
fill=
for i in $(seq 1 94); do fill="${fill}x"; done
for i in $(seq 1 100); do printf "%04d00$fill" $i; done | (read line; echo $line)
我在Python脚本中体验到了相同的行为(从终端接受的输入长度不超过4095,但从管道接受):
使用read(2)
,即使是C程序的工作原理也是一样的:
#包括
#包括
内部主(空)
{
char-buf[32768];
int sz=读取(0,buf,sizeof(buf)-1);
buf[sz]='\0';
printf(“读取行:[%s]\n”,buf);
返回0;
}
在所有情况下,我不能输入超过4095个字符的字符。输入提示将停止接受字符
问题1:在Linux系统(至少是Ubuntu 10.04和13.04)中,有没有一种方法可以交互读取超过4095个字符的终端
问题2:这一限制从何而来
受影响的系统:我注意到Ubuntu 10.04/x86和13.04/x86中存在此限制,但Cygwin(至少是最新版本)还没有截断超过10000个字符(因为我需要在Ubuntu中运行此脚本,所以没有进一步测试)。使用的终端:虚拟控制台和KDE
konsole
(Ubuntu13.04)和gnome终端
(Ubuntu10.04)。我没有解决方法,但我可以回答问题2。
在linux中,PIPE_BUF设置为4096(在limits.h
中),如果您对管道的写入超过4096,它将被截断
从/usr/include/linux/limits.h
:
#ifndef _LINUX_LIMITS_H
#define _LINUX_LIMITS_H
#define NR_OPEN 1024
#define NGROUPS_MAX 65536 /* supplemental group IDs are available */
#define ARG_MAX 131072 /* # bytes of args + environ for exec() */
#define LINK_MAX 127 /* # links a file may have */
#define MAX_CANON 255 /* size of the canonical input queue */
#define MAX_INPUT 255 /* size of the type-ahead buffer */
#define NAME_MAX 255 /* # chars in a file name */
#define PATH_MAX 4096 /* # chars in a path name including nul */
#define PIPE_BUF 4096 /* # bytes in atomic write to a pipe */
#define XATTR_NAME_MAX 255 /* # chars in an extended attribute name */
#define XATTR_SIZE_MAX 65536 /* size of an extended attribute value (64k) */
#define XATTR_LIST_MAX 65536 /* size of extended attribute namelist (64k) */
#define RTSIG_MAX 32
#endif
请参阅手册页的“规范和非规范模式”一节
通常,终端(标准输入)处于规范模式;在这种模式下,内核将在将输入返回到应用程序之前缓冲输入行。Linux的硬编码限制(${Linux\u source\u path}/include/Linux/TTY.h
中定义的N\u TTY\u BUF\u SIZE
)设置为4096,允许输入4095个字符,而不计算结束的新行。您还可以查看文件${linux\u source\u path}/drivers/tty/n\u tty.c
、函数n\u tty\u receive\u buf\u common()
以及上面的注释
在非规范模式下,默认情况下内核不会进行缓冲,一旦返回单个字符的输入(按下键),系统调用将立即返回。您可以操纵终端设置以读取指定数量的字符或设置非规范模式的超时,但每个termios(3)
手册页面的硬编码限制为4095(以及上述n_tty_receive_buf_common()
)
Bashread
内置命令仍在非规范模式下工作,如下所示:
IFS=$'\n' # Allow spaces and other white spaces.
stty -icanon # Disable canonical mode.
read line # Now we can read without inhibitions set by terminal.
stty icanon # Re-enable canonical mode (assuming it was enabled to begin with).
修改添加stty-icanon
后,您可以粘贴超过4096个字符的字符串,并使用bash
内置的read
命令成功读取该字符串(我成功尝试了超过10000个字符)
如果你把它放在一个文件中,也就是说,把它变成一个脚本,你可以使用
strace
查看调用的系统调用,你会看到read(2)
多次调用,每次在你向它键入输入时返回一个字符。问题肯定不是read();因为它最多可以读取任何有效的整数值。问题来自堆内存或管道大小。。因为它们是大小的唯一可能限制因素。是的,管道有这样一个限制,实际上需要注意的是,非交互式版本使用管道,并且必然会有多个写入和读取。但是我认为这个限制不应该影响终端输入(终端不是管道)。不,问题是终端规范模式的缓冲区大小。输入行是4096(为新行保留的最后一个字节)。原始提问者在回答中对此进行了解释和演示。他说答案还不完整,因为他还没有时间编写一个C程序来演示这一点,他无法指出在内核中这个限制是在哪里定义的。这就是我想说的,管道缓冲区大小是4096。可以使用“ulimit-p”进行检查,它将返回8作为答案,这意味着8*512字节=4096。因为每个字符是1字节,所以它只读取4095字节,最后一个字符是换行符,正如你所说的。我认为这是一个不同的常数。碰巧4096是默认页面大小,这解释了为什么在规范模式下最大管道大小和终端输入缓冲区的值恰好相同。在Unix和Linux中,有一个新的问题是由于有人在相同的限制上遇到了障碍,我从这个伟大的答案中借用了Linux内核代码的参考:
#ifndef _LINUX_LIMITS_H
#define _LINUX_LIMITS_H
#define NR_OPEN 1024
#define NGROUPS_MAX 65536 /* supplemental group IDs are available */
#define ARG_MAX 131072 /* # bytes of args + environ for exec() */
#define LINK_MAX 127 /* # links a file may have */
#define MAX_CANON 255 /* size of the canonical input queue */
#define MAX_INPUT 255 /* size of the type-ahead buffer */
#define NAME_MAX 255 /* # chars in a file name */
#define PATH_MAX 4096 /* # chars in a path name including nul */
#define PIPE_BUF 4096 /* # bytes in atomic write to a pipe */
#define XATTR_NAME_MAX 255 /* # chars in an extended attribute name */
#define XATTR_SIZE_MAX 65536 /* size of an extended attribute value (64k) */
#define XATTR_LIST_MAX 65536 /* size of extended attribute namelist (64k) */
#define RTSIG_MAX 32
#endif
IFS=$'\n' # Allow spaces and other white spaces.
stty -icanon # Disable canonical mode.
read line # Now we can read without inhibitions set by terminal.
stty icanon # Re-enable canonical mode (assuming it was enabled to begin with).