2013-08-02 75 views
11

在bash脚本中,我尝试从标准输入读取行,在设置IFS=$'\n'后使用内置的read命令。如果我将输入粘贴到读取中,则这些行将被截断为4095个字符的限制。这一限制似乎来自从终端阅读,因为这工作完全正常:Linux终端输入:从终端截取行读取用户输入,限制在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输入更长的时间,但是从管道接受):

#!/usr/bin/python 

from sys import stdin 

line = stdin.readline() 
print('%s' % line) 

即使C程序的工作原理相同,使用read(2)

#include <stdio.h> 
#include <unistd.h> 

int main(void) 
{ 
    char buf[32768]; 
    int sz = read(0, buf, sizeof(buf) - 1); 
    buf[sz] = '\0'; 
    printf("READ LINE: [%s]\n", buf); 
    return 0; 
} 

在所有情况下,我不能进入超过约4095个字符。输入提示停止接受字符。

问题-1:在Linux系统(至少Ubuntu 10.04和13.04)中,是否有一种方式可以从终端长度超过4095个字符进行交互式读取?

问题-2:这个限制来自哪里?

受影响系统:我在Ubuntu注意到了这个限制10.04/86和13.04/86,但Cygwin的(最新版本至少)还没有超过10000个字符(没有进一步测试,因为我需要得到这个截断在Ubuntu中工作的脚本)。使用的终端:虚拟控制台和KDE konsole(Ubuntu 13.04)和gnome-terminal(Ubuntu 10.04)。

回答

-1

我没有解决方法,但我可以回答问题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 
+0

是的管道有这样的限制,实际上它是相关的注意到,非交互版本使用管道,并且必然会有_几个写入和读取_。但我认为这个限制不应该影响终端输入(终端不是管道)。 – FooF

7

这是部分答案。 以非规范模式设置终端允许读取超过4096个字符(其中字符#4096需要成为新行)。

在bash脚本这可以这样做:

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个字符)。

终端线缓冲区的限制可能由内核设置。

TODO:

  1. C程序来证明这一点(使用tcgetattr()tcsetattr()
  2. 测试与Linux的/ x86_64体系 - 可能有不同的限制。
  3. 找到内核中定义的位置(也许在${linux_source_path}/include/linux/tty.h中定义的N_TTY_BUF_SIZE)。
-1

问题肯定不是read();因为它可以读取任何有效的整数值。问题来自堆内存或管道的大小..因为它们是大小的唯一可能的限制因素..

+0

不,问题是终端规范模式的缓冲区大小。输入行是4096(为新行保留的最后一个字节)。这在原始提问者的回答中得到解释和证明。他说这个答案并不完整,因为他还没有时间写一个C程序来证明这一点,而且他也不能指出这个限制在内核中的位置。 – FooF

+0

这就是我想说的,管道缓冲区大小是4096.它可以使用“ulimit -p”进行检查,它将返回8作为答案,这意味着8 * 512字节= 4096。由于每个字符都是1个字节,因此它只读取4095个字节,并且最后一个字符像换行符那样换行。 – Abhishek

+1

我认为这是一个不同的常数。正如它发生的那样,4096是默认页面大小,解释了为什么该值在规范模式下最大管道大小和终端输入缓冲区相同。 – FooF