Вход в терминал Linux: чтение пользовательского ввода с терминальных линий усечения при значении 4095 символов

В bash script я пытаюсь читать строки со стандартного ввода, используя встроенную команду read после установки IFS=$'\n'. Строки усекаются с пределом 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 script (не принимал дольше 4095 ввода от терминала, но принимал его из канала):

#!/usr/bin/python

from sys import stdin

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

Программа Even 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: Есть ли способ интерактивного чтения с терминала длиной более 4095 символов в системах Linux (по крайней мере, Ubuntu 10.04 и 13.04)?

Вопрос-2: Откуда взялось это ограничение?

Затрагиваемые системы: Я заметил это ограничение в Ubuntu 10.04/x86 и 13.04/x86, но Cygwin (по крайней мере, последняя версия) не обрезает еще более 10000 символов (не тестировалось дальше, так как я нужно, чтобы этот script работал в Ubuntu). Используемые терминалы: Виртуальная консоль и KDE konsole (Ubuntu 13.04) и gnome-terminal (Ubuntu 10.04).

Ответ 1

Это частичный ответ. Настройка терминала в неканоническом режиме позволяет читать более 4096 символов (где символ # 4096 должен быть новой строкой).

В bash script это можно сделать следующим образом:

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:

  • C, чтобы продемонстрировать это (используя tcgetattr() и tcsetattr())
  • Тест с архитектурой Linux/x86_64 - может иметь разные ограничения.
  • Найти, где в ядре это определено (возможно, N_TTY_BUF_SIZE определено в ${linux_source_path}/include/linux/tty.h).

Ответ 2

У меня нет обходного пути для вас, но я могу ответить на вопрос 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

Ответ 3

Проблема, безусловно, не в read(); так как он может читать до любого действительного целочисленного значения. Проблема возникает из памяти кучи или размера трубы.. поскольку они являются единственными возможными ограничивающими факторами размера.