Bagaimana membaca lebih dari input 4k tanpa baris baru di terminal?


25

Jadi saya punya banyak data TANPA GARIS BARU di clipboard (ini adalah file SVG besar pada satu baris). saya pergi

$ cat >file.svg

kemudian mencoba menempel (di Terminal Gnome), tetapi hanya karakter 4kB pertama yang diterima.

Saya menganggap ini adalah fitur / batasan readline.

Apakah ada cara untuk membaca dari STDIN yang akan menghindari masalah ini?

EDIT

Test case: Buat file demo. Yang ini akan memiliki ~ 4k "=" simbol diikuti oleh "bilah foo".

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

Salin itu ke clipboard Anda

xclip test.in

(jika Anda ingin klik tengah untuk menyisipkan) atau

xclip -selection clipboard test.in

(jika Anda ingin menggunakan Ctrl-Shift-Insert untuk melewatinya)

Kemudian cat >test.out, rekatkan (bagaimanapun caranya). Tekan Ctrl-D untuk mengakhiri streaming. cat test.out- Apakah kamu melihat "foo bar"?

Pada pengaturan saya (Ubuntu 12.04, Gnome Terminal, zsh) ketika saya tempel saya hanya melihat =dan saya tidak melihat foo bar. Sama ketika saya memeriksa test.out.


Apakah Anda yakin file SVG Anda sepenuhnya terbaca di clipboard Anda?
lororget

Apa masalah Anda yang sebenarnya? Bagaimana cara menyimpan konten clipboard ke file? Jika demikian, ada cara lain selain menempel di terminal.
lgeorget

berapa N dalam kasus Anda? Saya sudah mencobanya dengan 2kB data xml (termasuk LF) tidak ada masalah.
fduff

1
@artfulrobot Proses latar depan berinteraksi langsung dengan tty / pty. Shell tidak terlibat. Anda dapat melihat ini karena Anda tidak memiliki fitur readline (perintah edit / lompatan, histori, ...) dalam program jika mereka tidak menggunakan readline atau pustaka input lainnya.
jofel

1
Ini bukan batasan readline - readline dan bash tidak terlibat di sini. Ini adalah batasan antarmuka terminal.
Gilles 'SANGAT berhenti menjadi jahat'

Jawaban:


22

Jika saya memahami sumbernya dengan benar, di Linux, jumlah karakter maksimum yang dapat dibaca dalam sekali jalan terminal ditentukan oleh N_TTY_BUF_SIZEdalam sumber kernel. The nilai 4.096.

Ini adalah batasan antarmuka terminal, khususnya mode kanonik ("dimasak") yang menyediakan editor garis yang sangat kasar (backspace, enter, Ctrl+ Dpada awal baris untuk akhir file). Itu terjadi sepenuhnya di luar proses yang membaca.

Anda dapat mengganti terminal ke mode mentah, yang menonaktifkan pemrosesan garis. Itu juga menonaktifkan Ctrl+ Ddan hal-hal lain, membuat beban tambahan pada program Anda.

Ini adalah batasan Unix kuno yang tidak pernah diperbaiki karena ada sedikit motivasi. Manusia tidak memasuki garis panjang seperti itu. Jika Anda memasukkan input dari suatu program, Anda akan mengarahkan input program Anda dari file atau pipa.

Misalnya, untuk menggunakan konten papan klip X, pipa dari xselatau xclip. Dalam kasus Anda:

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

Hapus -batau -selection clipboarduntuk menggunakan pilihan X (yang ditetapkan dengan menyorot dengan mouse) daripada clipboard.

Di OSX, gunakan pbpasteuntuk menempelkan konten clipboard (dan pbcopyuntuk mengaturnya).

Anda dapat mengakses papan klip X melalui SSH jika Anda mengaktifkan penerusan X11 ssh -X(yang mungkin dilarang oleh beberapa server). Jika Anda hanya dapat menggunakan sshtanpa penerusan X11, Anda dapat menggunakan scp, sftpatau sshfsuntuk menyalin file.

Jika menempel adalah satu-satunya solusi karena Anda tidak dapat meneruskan clipboard atau Anda tidak menempel tetapi misalnya memalsukan mengetik ke mesin virtual, pendekatan alternatif adalah menyandikan data menjadi sesuatu yang memiliki baris baru. Base64 sangat cocok untuk ini: ia mengubah data sewenang-wenang menjadi karakter yang dapat dicetak, dan mengabaikan spasi ketika mendekode. Pendekatan ini memiliki keunggulan tambahan yang mendukung data sewenang-wenang dalam input, bahkan mengontrol karakter yang akan ditafsirkan terminal ketika menempel. Dalam kasus Anda, Anda dapat menyandikan konten:

xsel -b | base64 | xsel -b

lalu decode:

base64 -d
 Paste
Ctrl+D

Perhatikan ada bug korupsi data yang benar-benar jahat ketika menggunakan xseldengan> 4k byte: github.com/kfish/xsel/issues/14
Patrick

14

Batas Anda menjalankan ke dalam adalah ukuran maksimum garis di mode input kanonik , MAX_CANON.

Dalam mode input kanonik, driver tty menyediakan layanan pengeditan garis dasar sehingga program userspace tidak perlu. Ini tidak memiliki hampir fitur sebanyak readline, tetapi mengenali beberapa karakter khusus yang dapat dikonfigurasi seperti menghapus (biasanya Backspace atau Hapus) dan membunuh (biasanya Ctrl-U).

Yang paling penting untuk pertanyaan Anda, input mode kanonik buffer hingga karakter end-of-line terlihat. Karena buffer ada dalam driver tty, dalam memori kernel, itu tidak terlalu besar.

Anda dapat mematikan mode kanonik dengan stty cbreakatau stty -icanon, lalu lakukan tempel. Ini memiliki kerugian signifikan bahwa Anda tidak akan dapat mengirim EOF dengan Ctrl-D. Itu salah satu hal yang menjadi tanggung jawab mode kanonik. Anda masih dapat menghentikan catdengan Ctrl-C karena karakter penghasil sinyal dikontrol oleh flag yang terpisah ( stty rawatau stty -isig).

Misteri bagi saya adalah mengapa, karena Anda sudah menunjukkan bahwa Anda tahu tentang xclip, Anda tidak hanya menggunakan xclip -o > filebukannyacat


1
Misteri dapat dengan mudah dipecahkan: Tampaknya artfulrobot ingin dengan cepat mengisi file pada host jarak jauh dengan data dari clipboard. Di shell jarak jauh, biasanya tidak ada akses langsung ke clipboard lokal via xclip.
jofel

3
Ah, upload-by-paste yang bagus. Jika saya harus melakukan salah satu dari itu dan itu bukan teks biasa, saya akan menggunakan kode itu daripada mencoba meyakinkan pengemudi tty untuk melewatinya. Teks biasa dengan garis besar dapat ditangani dengan cara itu juga.

2

Jika kamu melakukan:

stty eol =

Dan kemudian jalankan demo yang disarankan di EDIT Anda, Anda akan melihat bilah foo di cetakan test.out . Baris disiplin terminal akan flush output nya ke pembacanya seperti membaca setiap khusus eol char dalam masukan Anda.

Terminal mode kanonik Linux - seperti yang dapat dikonfigurasi dengan stty icanonatau mungkin hanya stty sane- menangani karakter input khusus berikut ...

  • eof
    • default: ^D
    • Menghentikan jalur input dan menyiram output ke pembaca. Karena dihapus dari input, jika input sebagai satu-satunya karakter pada sebuah baris, ia dilewatkan sebagai pembacaan nol - atau akhir file - ke pembaca.
  • eol
    • default: tidak ditugaskan
    • Juga mengakhiri jalur input, tetapi tidak dihapus dari input.
  • membunuh
    • default: ^U
    • Hapus semua input yang disangga.
  • menghapus
    • default: ^H (atau mungkin @atau ^?pada beberapa sistem)
    • Menghapus karakter input buffered terakhir.

Ketika iexten juga diatur - seperti stty icanon iextenatau, sekali lagi, mungkin hanya stty sane, terminal Linux kanonik juga akan menangani ...

  • eol2
    • default: belum ditetapkan
    • Juga juga mengakhiri jalur input, dan juga tidak dihapus dari input.
  • werase
    • default: ^W
    • Menghapus kata input buffered terakhir .
  • rprnt
    • default: ^R
    • Mencetak ulang semua input yang disangga.
  • Selanjutnya
    • default: ^V
    • Menghapus signifikansi khusus sejauh menyangkut disiplin garis untuk segera karakter input berikut.

Karakter-karakter ini ditangani dengan menghapusnya dari aliran input - kecuali eol dan eol2 , yaitu - dan melakukan fungsi khusus yang terkait sebelum meneruskan aliran yang diproses ke pembaca - yang biasanya merupakan shell Anda, tetapi dapat berupa apa pun yang dilakukan oleh grup proses latar depan .

Karakter input khusus lainnya yang ditangani serupa tetapi dapat dikonfigurasikan secara independen dari pengaturan icanon apa pun termasuk set isig seperti stty isigdan mungkin juga termasuk dalam konfigurasi waras :

  • berhenti
    • default: ^\
    • Siram semua input yang disangga (jika noflsh tidak diatur) dan mengirimkan SIGQUIT ke grup proses latar depan - kemungkinan menghasilkan dump inti.
  • susp
    • default: ^Z
    • Flush semua input buffered (jika noflsh tidak diatur) dan mengirimkan SIGTSTP ke grup proses foreground. Kelompok proses yang ditangguhkan kemungkinan dapat dilanjutkan dengan salah satu kill -CONT "$!"atau hanya fgdalam ( set -m) shell yang dikendalikan pekerjaan.
  • intr
    • default: ^C
    • Siram semua input yang disangga (jika noflsh tidak diatur) dan mengirimkan SIGINT ke grup proses latar depan.

Dan set ixon - dikonfigurasi seperti stty ixondan juga biasanya termasuk dalam konfigurasi waras :

  • berhenti
    • default: ^S
    • Hentikan semua output ke pembaca hingga mulai dibaca dalam input atau - ketika ixany juga diatur - setidaknya satu karakter lagi dibaca.
  • mulai
    • default: ^Q
    • Restart output jika sebelumnya telah dihentikan dengan berhenti .
  • Baik berhenti dan mulai dihapus dari input saat diproses, tetapi jika output dimulai kembali karena setiap karakter dalam input ketika ixany diatur maka karakter itu tidak dihapus.

Karakter khusus yang ditangani pada sistem non-Linux lainnya mungkin termasuk ...

  • menyiram
    • default: ^O
    • Mengalihkan pembuangan dan pembilasan input yang disangga dan dihapus dari input.
  • dsusp
    • default: belum ditetapkan
    • Siram semua input yang disangga hanya ketika pembaca membaca karakter input khusus yang ditugaskan kemudian mengirimkan SIGTSTP.

Dan mungkin...

  • swtch
    • default ^@ (artinya \0atau NUL)
    • Mengalihkan foreground shell-layers. Untuk digunakan dengan aplikasi shl shell-layer pada beberapa sistem.
    • Implementasi shlyang multipleks ptys dan karenanya kompatibel dengan kontrol pekerjaan daripada perilaku swtch yang bergantung pada implementasi asli dapat secara bebas dimiliki dalam heirloom-toolchesttool suite.

Untuk gambaran yang lebih jelas tentang bagaimana dan mengapa (dan mungkin mengapa tidak) fungsi input ini ditangani berkonsultasi man 3 termios.

Semua fungsi di atas dapat ditugaskan (atau dipindahkan) - jika ada - seperti sttyfunction assigned-key. Untuk menonaktifkan fungsi tunggal lakukan . Sebagai alternatif, karena berbagai upaya dengan penugasan untuk fungsi pengeditan baris yang disebutkan di atas dengan semua implementasi GNU, AST, atau heirloom tampaknya menunjukkan, Anda juga dapat sebagai penugasan NUL untuk fungsi apa pun tampaknya sama dengan mengaturnya agar tidak ditugaskan di linux saya. sistem.sttyfunction^-sttysttyfunction^@

Mungkin Anda memang melihat gema dari karakter-karakter ini ketika Anda mengetikkannya (karena kemungkinan dapat dikonfigurasi dengan [-] ctlecho ) , tetapi ini hanya penanda untuk menunjukkan di mana Anda melakukannya - program yang menerima input Anda tidak memiliki gagasan bahwa Anda ketik mereka (kecuali eol [2] , yaitu) dan hanya menerima salinan input Anda yang telah diterapkan disiplin disiplin efeknya.

Konsekuensi dari penanganan terminal terhadap berbagai fungsi pengeditan garis adalah bahwa ia harus memerlukan buffer input sampai batas tertentu agar dapat bertindak berdasarkan fungsi yang Anda tunjukkan kepadanya bahwa ia seharusnya - dan dengan demikian tidak mungkin ada pasokan input tanpa batas yang Anda bisa membunuh kapan saja . The garis buffer lebih tepatnya membunuh penyangga.

Jika Anda menetapkan karakter eol atau eol2 ke beberapa pembatas yang terjadi pada input - bahkan jika tidak ada baris baru atau karakter kembali, misalnya - maka Anda hanya akan dapat membunuh hingga titik yang terakhir terjadi dan buffer kill Anda akan meluas sejauh mungkin sampai selanjutnya - atau baris baru (atau kembali jika icrnl diatur dan igncr tidak) - terjadi pada input.


1

catakan menerima sejumlah karakter, seperti yang Anda saksikan dengan melakukan misalnya cat /dev/random > test.bin(jangan lakukan itu kecuali Anda tahu cara menghentikannya :). Saya mencoba menyalin dan menempelkan file besar ke dalamnyacat > test.txt . Semua baris berakhir di file apakah saya dibatalkan dengan Ctrl- catau Ctrl- d, tetapi dalam kasus sebelumnya tidak semua baris dicetak ke terminal . Saya percaya ini karena catbuffer pencetakannya, menunggu buffer teks lengkap atau input langsung dari terminal sebelum setiap pencetakan.

Pada sistem saya, saya pikir ukuran buffer adalah 4096 (2 ^ 12) byte: Buat file menggunakan 4095 byte (printf '1234567890%.0s' {1..409} && printf 12345) > test.in, muat ke buffer copy menggunakan xclip test.in, mulai cat > test.out, tempel menggunakan Shift- Insert, dan akhiri aliran dengan menekan Ctrl- d. Sekarang tambahkan byte menggunakan printf '6' >> test.in, dan aliran dicetak dua kali : Sekali dalam catoutput (semua 4096 byte), dan 4095 byte terakhir lagi pada shell setelah berakhir.


+1 Dalam kasus saya, itu juga tergantung pada clipboard yang digunakan. Jika saya menggunakan buffer pemilihan (tempel klik tengah) saya hanya melihat 4542 baris pertama dari data pengujian saya (tetapi semuanya berakhir di file yang dibuat) tetapi menggunakan clipboard X (Ctrl + C / Ctrl + V) Saya melihat semua itu. Dalam kedua kasus semua data dicetak ke dalam file yang dihasilkan tetapi dalam mantan hanya sebagian data ditampilkan di terminal.
terdon

1
Saya tidak mendapatkan perilaku yang sama. Lihat pertanyaan yang diedit
artfulrobot

0

Salah satu solusinya adalah menempelkannya ke editor yang mendukung garis panjang, misalnya vim.

Jika Anda menggunakan vim, pertama-tama masukkan mode tempel dengan :pastesebelum memasukkan mode sisipan dengan idan menempelkan teks.

Dengan menggunakan situs kami, Anda mengakui telah membaca dan memahami Kebijakan Cookie dan Kebijakan Privasi kami.
Licensed under cc by-sa 3.0 with attribution required.