Як читати понад 4 к введення без нових рядків на терміналі?


25

Тому у мене в буфері обміну дуже багато даних БЕЗ НОВИХ ЛІНІЙ (це великий SVG-файл у одному рядку). я пішов

$ cat >file.svg

потім спробували вставити (у терміналі Gnome), але були прийняті лише перші 4 кБ символи.

Я припускаю, що це особливість чи обмеження для читання ліній.

Чи є спосіб прочитати з STDIN, який би уникнув цієї проблеми?

EDIT

Тестовий випадок: Створіть демонстраційний файл. Цей символ матиме ~ 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.


Ви впевнені, що ваш файл SVG повністю зачитаний у буфер обміну?
lgeorget

Яка ваша актуальна проблема? Як зберігати вміст буфера обміну у файлі? Якщо так, то в терміналі є інший спосіб, ніж вклеювання.
lgeorget

скільки N у вашому випадку? Я спробував це з 2kB xml даних (включаючи LF) без проблем.
fduff

1
@artfulrobot Процес переднього плану взаємодіє безпосередньо з tty / pty. Оболонка не бере участь. Це ви можете бачити, оскільки у вас немає функцій для читання (редагування / стрибки команд, історія, ...) у програмах, якщо вони самі не використовують читальну лінію чи будь-яку іншу бібліотеку вводу.
jofel

1
Це не обмеження читання рядків - readline та bash тут не задіяні. Це обмеження термінального інтерфейсу.
Жил 'ТАК - перестань бути злим'

Відповіді:


22

Якщо я правильно розумію джерело, в 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встановити його).

Ви можете отримати доступ до буфера обміну X через SSH, якщо активувати переадресацію X11 ssh -X(що деякі сервери можуть заборонити). Якщо ви можете використовувати тільки sshбез перенаправлення X11, ви можете використовувати scp, sftpабо sshfsскопіювати файл.

Якщо вставлення - єдине рішення, оскільки ви не можете переслати буфер обміну або не вставляєте його, але, наприклад, підробка вводу у віртуальну машину, альтернативним підходом є кодування даних у те, що має нові рядки. Для цього Base64 добре підходить: він перетворює довільні дані в друковані символи та ігнорує пробіл під час декодування. Цей підхід має додаткову перевагу в тому, що він підтримує довільні дані на вході, навіть символи управління, які термінал інтерпретуватиме під час вставки. У вашому випадку ви можете кодувати вміст:

xsel -b | base64 | xsel -b

потім розшифруйте його:

base64 -d
 Paste
Ctrl+D

Зауважте, що при використанні xselз> 4k байтами справді неприємна помилка даних : github.com/kfish/xsel/issues/14
Патрік,

14

Граничне ви біжите в це максимальний розмір рядка в режимі канонічного введення , MAX_CANON.

У канонічному режимі введення драйвер tty надає основні послуги з редагування рядків, тому програмі простору користувачів цього не потрібно. Він не має майже стільки функцій, як readline, але він розпізнає кілька настроюваних спеціальних символів, таких як стирання (як правило, Backspace або Delete) та kill (зазвичай Ctrl-U).

Найголовніше, що стосується вашого питання, вводить буфери канонічного режиму, поки не з’явиться символ кінця рядка. Оскільки буфер знаходиться в драйвері tty, в пам'яті ядра, він не дуже великий.

Ви можете вимкнути канонічний режим за допомогою stty cbreakі stty -icanon, а потім виконати пасту. Це має істотний недолік у тому, що ви не зможете відправити EOF за допомогою Ctrl-D. Це ще одна з речей, за які відповідає канонічний режим. Ви все одно зможете припинити використання catCtrl-C, оскільки символи, що генерують сигнал, управляються окремим прапором ( stty rawабо stty -isig).

Для мене таємниця, чому, оскільки ви вже продемонстрували, що знаєте про xclip, ви не просто використовуєте xclip -o > fileзамість цьогоcat


1
Таємницю можна легко розгадати: схоже, artfulrobot хоче швидко заповнити файл на віддалених хостах даними з буфера обміну. У віддаленій оболонці зазвичай немає прямого доступу до локального буфера обміну через xclip.
jofel

3
Ах, старий добрий додавання-вставка. Якби мені довелося зробити одне з них, і це був не звичайний текст, я би його uuencode замість того, щоб намагатись переконати драйвер Tty пропустити його. Звичайний текст із величезними рядками теж може бути оброблений.

2

Якщо ти зробиш:

stty eol =

А потім запустіть демонстрацію, запропоновану у вашому редагуванні , ви побачите смужку foo у роздруківці test.out . Лінійна дисципліна терміналу передасть свій вихід своєму читачеві, коли він читатиме кожен спеціальний графік eol у вашому введенні.

Термінал канонічного режиму Linux - як це можна налаштувати stty icanonабо, можливо, просто stty sane- обробляє наступні спеціальні символи введення ...

  • еоф
    • за замовчуванням: ^D
    • Припиняє рядок введення та передає вихід на зчитувач. Оскільки він видаляється з введення, якщо він є єдиним символом у рядку, він передається читачеві з нульовим читанням або кінцем файлу .
  • еол
    • за замовчуванням: без призначення
    • Також завершує рядок введення, але його не видаляють із введення.
  • вбити
    • за замовчуванням: ^U
    • Стирає всі буферні дані.
  • стерти
    • за замовчуванням: ^H (або, можливо, @або ^?в деяких системах)
    • Стирає останній буферний вхідний символ.

Коли iexten також встановлений - як, stty icanon iextenабо знову ж таки, мабуть, просто stty sane, канонічний термінал Linux також буде обробляти ...

  • eol2
    • за замовчуванням: не призначено
    • Крім того, також завершує вхідні лінію, і також не будуть видалені з вхідного сигналу.
  • стерти
    • за замовчуванням: ^W
    • Стирає останнє буферне вхідне слово .
  • rprnt
    • за замовчуванням: ^R
    • Передрукує всі буферні дані.
  • наступний
    • за замовчуванням: ^V
    • Знімає будь-яке особливе значення, що стосується дисципліни рядків для безпосередньо наступного символу введення.

Цими символами обробляються, видаляючи їх із вхідного потоку - за винятком eol та eol2 , тобто - та виконуючи пов'язану спеціальну функцію перед передачею обробленого потоку в зчитувач - що зазвичай є вашою оболонкою, але може бути будь-якою групою процесу переднього плану .

Інші спеціальні вхідні символи, які аналогічно обробляються, але можуть бути налаштовані незалежно від будь- яких параметрів icoon , включають набір isig - набір як stty isigі, ймовірно, також включений у здорову конфігурацію:

  • кинути
    • за замовчуванням: ^\
    • Очищає весь буферний вхід (якщо параметр noflsh не встановлений) і надсилає SIGQUIT до групи переднього плану процесів - ймовірно, генеруючи ядро-дамп.
  • сусп
    • за замовчуванням: ^Z
    • Промиває весь буферний вхід (якщо параметр noflsh не встановлений) та надсилає SIGTSTP до групи процесу переднього плану. Припинена група процесів, можливо, може бути відновлена ​​з будь-якою kill -CONT "$!"або просто fgв ( set -m) контрольованій роботі оболонці.
  • intr
    • за замовчуванням: ^C
    • Очищує весь буферний вхід (якщо параметр noflsh не встановлений) та надсилає SIGINT до групи процесу переднього плану.

І набір ixon - налаштований як, stty ixonа також зазвичай включається в здоровий конфігурацію:

  • Стоп
    • за замовчуванням: ^S
    • Зупиняє весь вихід на зчитувач до тих пір, поки не буде прочитано будь-який запуск на вході або - коли ixany також встановлено - принаймні ще один символ буде прочитаний.
  • почати
    • за замовчуванням: ^Q
    • Перезавантажує вихід, якщо він раніше був зупинений із зупинкою .
  • Як зупинка, так і запуск видаляються з вхідних даних під час обробки, але якщо результат перезапускається через будь-який символ вхідного сигналу, коли встановлено ixany , цей символ не видаляється.

Спеціальні символи, що обробляються в інших системах, що не є Linux, можуть включати ...

  • рум'янець
    • за замовчуванням: ^O
    • Вмикає викидання та промивання буферизованого входу та видаляється з входу.
  • суп
    • за замовчуванням: не призначено
    • Промиває весь буферний вхід лише тоді, коли зчитувач зчитує призначений спеціальний символ введення, а потім надсилає SIGTSTP.

І можливо ...

  • swtch
    • за замовчуванням ^@ (означає \0або NUL)
    • Перемикає шари оболонок переднього плану. Для використання із застосуванням shl шарів оболонок у деяких системах.
    • Реалізація shlяких мультиплексує ptys і, таким чином, сумісна з контролем роботи, а не оригінальною поведінкою, що залежить від swtch, може вільно матись у heirloom-toolchestнаборі інструментів.

Для більш чіткого уявлення про те, як і чому (а може, чому і ні) ці вхідні функції обробляються, див man 3 termios.

Усі перераховані вище функції можуть бути призначені (або перепризначені), коли це застосовується - як sttyfunction assigned-key. Щоб відключити будь-яку одну функцію, виконайте . Альтернативно, як різні спроби з завданнями для будь-якого з вищевказаних ліній редагуванням функцій з усіма GNU, AST, або сімейна реліквія в реалізаціях , здається, вказують, ви можете також , як NUL призначення для будь-якої функції , здається , прирівняти встановити його в Unassigned на моєму Linux система.sttyfunction^-sttysttyfunction^@

Ймовірно, ви бачите відлуння цих символів, коли ви вводите їх (як це може бути налаштовано w / [-] ctlecho ) , але це лише маркер, щоб показати вам, куди ви потрапили - програма, що отримує ваш вхід, не має поняття, що ви вводить їх (крім eol [2] , тобто) і отримує лише копію вашого вводу, до якого лінійна дисципліна застосувала свої ефекти.

Наслідком обробки терміналом різних функцій редагування рядків є те, що він повинен до деякої міри потребувати буфера введення для того, щоб діяти на функції, які ви йому вказуєте, що це повинно - і тому не може бути необмеженої подачі вводу, який ви можете в будь-який час вбити . Лінія буфер точніше вбити буфера.

Якщо ви встановите Eol або EOL2 символи в якій - то роздільник , який відбувається на вході - навіть якщо ні один не символ перекладу рядка або повернення символів, наприклад , - тоді ви будете тільки в стані вбити до такої міри , що це в останній раз відбулося і ваш вбити буфер не поширюватиметься, наскільки це можливо , поки що прямує з них - або перекладу рядка (або повернення , якщо ICRNL встановлений і IGNCR немає) - відбувається на вході.


1

catприйме будь-яку кількість символів, як ви могли засвідчити, зробивши, наприклад, cat /dev/random > test.bin(не робіть цього, якщо ви не знаєте, як це зупинити :). Я спробував скопіювати та вставити великий файл у cat > test.txt. Усі рядки потрапили у файл, незалежно від того, чи я скасовував Ctrl- cабо Ctrl- d, але в першому випадку не всі рядки були надруковані до терміналу . Я вважаю, що catбуферизація друкується, очікуючи повного буфера тексту або прямого введення з терміналу перед кожною друком.

У моїй системі я вважаю, що розмір буфера становить 4096 (2 ^ 12) байт: Створіть файл розміром 4095 байт (printf '1234567890%.0s' {1..409} && printf 12345) > test.in, завантажте його в буфер копіювання за допомогою xclip test.in, запустіть cat > test.out, вставте за допомогою Shift- Insertі завершіть потік натисканням Ctrl- d. Тепер додайте байт за допомогою printf '6' >> test.in, і потік друкується двічі : Один раз у catвиводі (всі 4096 байт), а останні 4095 байт знову на оболонці після закінчення.


+1 У моєму випадку це також залежало від використовуваного буфера обміну. Якщо я використовував буфер вибору (вставити середній клік), я побачив лише перші 4542 рядки моїх тестових даних (але всі вони опинилися у створеному файлі), але за допомогою буфера обміну X (Ctrl + C / Ctrl + V) я побачив все це. В обох випадках усі дані були надруковані в отриманий файл, але в першому лише часткові дані були показані в терміналі.
тердон

1
Я не маю такої ж поведінки. Дивіться відредаговане запитання
artfulrobot

0

Одне рішення - вставити його в редактор, який підтримує довгі рядки, наприклад, vim.

Якщо ви використовуєте vim, спочатку введіть пастовий режим, :pasteперш ніж увійти в режим iвставки та вставити текст.

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.