如何在终端上读取超过 4k 的输入而不换行?

如何在终端上读取超过 4k 的输入而不换行?

所以我有很多数据没有新线路剪贴板上(这是一个大型 SVG 文件,一行)。我去了

$ cat >file.svg

然后尝试粘贴(在 Gnome 终端中),但只接受前 4kB 字符。

我认为这是一个阅读行功能/限制。

有没有办法从 STDIN 读取数据来避免这个问题?

编辑

测试用例:创建一个演示文件。这个将有大约 4k 个“=”符号,后跟“foo bar”。

{ printf '=%.0s' {1..4095} ; echo "foo bar" ; } > test.in

将其复制到剪贴板

xclip test.in

(如果您想中键单击插入)或

xclip -selection clipboard test.in

(如果你想使用 Ctrl-Shift-Insert 将其粘贴进去)

然后cat >test.out,粘贴(无论哪种方式)。按 Ctrl-D 结束流。cat test.out- 你看到“foo bar”了吗?

在我的设置(Ubuntu 12.04、Gnome 终端、zsh)上,当我粘贴时,我只看到 ,=而没有看到foo bar.我检查时也一样test.out

答案1

如果我对源代码的理解正确的话,在Linux下,终端上一次可以读取的最大字符数由下式决定:N_TTY_BUF_SIZE在内核源代码中。这价值是 4096。

这是终端接口的限制,特别是规范(“熟”)模式它提供了一个极其粗糙的行编辑器(退格键、回车键、行首的Ctrl+D表示文件结尾)。它完全发生在阅读过程之外。

您可以将终端切换到原始模式,这会禁用行处理。它还禁用Ctrl+D和其他细节,给您的程序带来额外的负担。

这是一个古老的 Unix 限制,由于缺乏动力而从未得到修复。人类不会排这么长的队。如果您从程序提供输入,则可以从文件或管道重定向程序的输入。

例如,要使用 X 剪贴板的内容,请使用管道xsel或者xclip。在你的情况下:

xsel -b >file.svg
xclip -selection clipboard >file.svg

删除-b-selection clipboard使用 X 选择(通过鼠标突出显示设置的选择)而不是剪贴板。

在 OSX 上,使用pbpaste粘贴剪贴板内容(并pbcopy设置它)。

如果您激活 X11 转发ssh -X(某些服务器可能会禁止),您可以通过 SSH 访问 X 剪贴板。如果只能使用ssh而无需X11转发,则可以使用scpsftpsshfs来复制文件。

如果粘贴是唯一的解决方案,因为您无法转发剪贴板,或者您没有粘贴,但例如伪造输入到虚拟机中,则另一种方法是将数据编码为具有换行符的内容。Base64非常适合于此:它将任意数据转换为可打印字符,并在解码时忽略空格。这种方法还有一个额外的优点,即它支持输入中的任意数据,甚至是终端在粘贴时解释的控制字符。对于您的情况,您可以对内容进行编码:

xsel -b | base64 | xsel -b

然后解码它:

base64 -d
 Paste
Ctrl+D

答案2

您遇到的限制是行的最大大小规范输入模式, MAX_CANON.

在规范输入模式下,tty 驱动程序提供基本的行编辑服务,因此用户空间程序不需要这样做。它没有 readline 那么多的功能,但它可以识别一些可配置的特殊字符,例如擦除(通常是退格键或删除)和终止(通常是 Ctrl-U)。

对于您的问题,最重要的是,规范模式会缓冲输入,直到看到行尾字符。因为缓冲区位于 tty 驱动程序中,位于内核内存中,所以它不是很大。

stty cbreak您可以使用或关闭规范模式stty -icanon,然后进行粘贴。这有一个显着的缺点,即您将无法使用 Ctrl-D 发送 EOF。这是规范模式负责的另一件事。您仍然可以cat使用 Ctrl-C 终止,因为信号生成字符由单独的标志(stty rawstty -isig)控制。

对我来说,神秘的是为什么,既然你已经证明你知道xclip,你不只是使用xclip -o > file而不是cat

答案3

如果你这样做:

stty eol =

然后运行您中建议的演示编辑, 你会看见富酒吧在打印输出中检验出。终端的线路规则将在读取每个特殊字符时将其输出刷新到读取器停产您输入的字符。

Linux 规范模式终端 - 可以配置stty icanon或可能只是stty sane- 处理以下特殊输入字符......

  • 埃夫
    • 默认:^D
    • 终止输入线并将输出刷新到读取器。因为它已从输入中删除,所以如果它作为一行中唯一的字符输入,则会作为无效的读 - 或文件结尾- 致读者。
  • 停产
    • 默认值:未分配
    • 也终止输入行,但不会从输入中删除。
    • 默认:^U
    • 擦除所有缓冲输入。
  • 擦除
    • 默认:^H (或者可能@^?在某些系统上)
    • 擦除最后一个缓冲的输入字符。

什么时候扩展也被设置 - 就像stty icanon iexten或者,再一次,可能只是stty sane,一个规范的 Linux 终端也将处理......

  • 停产2
    • 默认值:未分配
    • 终止输入行,并且是未从输入中删除。
  • 韦拉塞
    • 默认:^W
    • 擦除最后缓冲的输入单词
  • 转数
    • 默认:^R
    • 重新打印所有缓冲的输入。
  • 下一个
    • 默认:^V
    • 就行规则而言,删除紧随其后的输入字符的任何特殊意义。

这些字符的处理方式是从输入流中删除它们 - 例外停产停产2,即 - 并在将处理后的流传递给读取器之前执行关联的特殊功能 - 这通常是您的 shell,但也可以是任何前台进程组。

其他特殊输入字符的处理方式类似,但可以独立于任何字符进行配置伊卡农设置包括伊西格设置 - 设置类似stty isig并且可能也包含在理智的配置:

  • 辞职
    • 默认:^\
    • 刷新所有缓冲输入(如果诺夫尔什未设置)并将 SIGQUIT 发送到前台进程组 - 可能会生成核心转储。
  • 悬念
    • 默认:^Z
    • 刷新所有缓冲输入(如果诺夫尔什未设置)并将 SIGTSTP 发送到前台进程组。挂起的进程组可以通过以下任一方式kill -CONT "$!"恢复fg( set -m)作业控制的 shell。
  • 整数
    • 默认:^C
    • 刷新所有缓冲输入(如果诺夫尔什未设置)并将 SIGINT 发送到前台进程组。

还有伊克松set - 配置类似stty ixon并且通常也包含在理智的配置:

  • 停止
    • 默认:^S
    • 停止向阅读器的所有输出,直到开始在输入中读取或 - 当伊克萨尼还设置了 - 至少又读取了一个字符。
  • 开始
    • 默认:^Q
    • 如果先前已停止输出,则重新启动输出停止
  • 两者的停止开始处理时从输入中删除,但如果由于输入中的任何字符而重新启动输出伊克萨尼设置后该字符不会被删除。

在其他非 Linux 系统上处理的特殊字符可能包括...

  • 冲水
    • 默认:^O
    • 切换缓冲输入的丢弃和刷新,并从输入中删除。
  • 杜斯普
    • 默认值:未分配
    • 仅当读取器读取指定的特殊输入字符然后发送 SIGTSTP 时,才刷新所有缓冲的输入。

并且可能...

  • 开关
    • 默认^@ (意思是\0NUL
    • 切换前景 shell 层。与使用shl 壳层在某些系统上的应用。
    • 一个实现shl它复用了 pty,因此与作业控制兼容,而不是原始实现的开关依赖行为可以自由地发生在heirloom-toolchest工具套件。

更清楚地了解如何以及为何(也许为什么不呢)这些输入函数的处理请参考man 3 termios

以上所有功能均可分配(或重新分配)- 适用时 - 像sttyfunction assigned-key。要禁用任何单个功能,请执行以下操作sttyfunction^-。或者,正如对所有 GNU、AST 或传家宝实现的任何上述行编辑功能的分配的各种尝试stty似乎表明的那样,您也可以sttyfunction^@作为零点任何函数的赋值似乎等同于将其设置为未分配的在我的Linux系统上。

也许你确实看到了回声当您键入这些字符时(可能可以配置为[-]克特莱乔,但这只是一个标记,用于显示您所做的操作 - 接收您输入的程序并不知道您输入了它们(除了停产[2], 那是)并仅收到您输入的副本,线路纪律已对其应用其效果。

终端处理各种行编辑功能的一个结果是,它必须需要在某种程度上缓冲输入,以便对您指示它应该执行的功能起作用 - 因此不可能有无限的输入供应你可能随时。这线缓冲区更准确地说是缓冲。

如果您设置停产或者停产2输入中出现的某些分隔符的字符 - 例如,即使既不是换行符也不是返回字符 - 那么你只能直到它最后一次发生并且你的缓冲区将尽可能地扩展,直到下一个或换行符(或者返回,如果icrnl已设置并且忽略不是)- 出现在输入中。

答案4

一种解决方案是将其粘贴到支持长行的编辑器中,例如 vim。

如果您使用 vim,请先进入粘贴模式,:paste然后再进入插入模式i并粘贴文本。

相关内容