Làm thế nào để đọc hơn 4k đầu vào mà không có dòng mới trên thiết bị đầu cuối?


25

Vì vậy, tôi có rất nhiều dữ liệu KHÔNG CÓ DÒNG MỚI trên bảng tạm (đó là tệp SVG lớn trên một dòng). tôi đã đi

$ cat >file.svg

sau đó cố gắng dán (trong Gnome Terminal), nhưng chỉ các ký tự 4kB đầu tiên được chấp nhận.

Tôi giả sử đây là một tính năng / giới hạn đọc.

Có cách nào để đọc từ STDIN sẽ tránh được vấn đề này không?

CHỈNH SỬA

Trường hợp thử nghiệm: Tạo một tệp demo. Cái này sẽ có ~ 4k "=" ký hiệu theo sau là "foo bar".

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

Sao chép nó vào clipboard của bạn

xclip test.in

(nếu bạn muốn nhấp chuột giữa để chèn) hoặc

xclip -selection clipboard test.in

(nếu bạn muốn sử dụng Ctrl-Shift-Chèn để qua nó trong)

Sau đó cat >test.out, dán (cách nào). Nhấn Ctrl-D để kết thúc luồng. cat test.out- bạn có thấy "thanh foo" không?

Trên thiết lập của tôi (Ubuntu 12.04, Gnome Terminal, zsh) khi tôi dán tôi chỉ thấy =và tôi không thấy foo bar. Tương tự khi tôi kiểm tra test.out.


Bạn có chắc chắn tệp SVG của bạn đã được đọc hoàn toàn vào clipboard của bạn?
lgeorget

Vấn đề thực sự của bạn là gì? Làm thế nào để lưu trữ nội dung của clipboard vào một tập tin? Nếu vậy, có cách khác hơn là dán trong thiết bị đầu cuối.
lgeorget

N trong trường hợp của bạn là bao nhiêu? Tôi đã thử nó với 2kB dữ liệu xml (inc LF) không có vấn đề gì.
fduff

1
@artfulrobot Một quá trình tiền cảnh tương tác trực tiếp với tty / pty. Vỏ không liên quan. Bạn có thể thấy điều này bởi vì bạn không có các tính năng đọc (chỉnh sửa / lệnh nhảy, lịch sử, ...) trong các chương trình nếu chúng không sử dụng đường đọc hoặc bất kỳ thư viện đầu vào nào khác.
jofel

1
Đây không phải là giới hạn về đường đọc - đường đọc và bash không liên quan ở đây. Đó là một hạn chế của giao diện đầu cuối.
Gilles 'SO- ngừng trở nên xấu xa'

Câu trả lời:


22

Nếu tôi hiểu chính xác nguồn, trong Linux, số lượng ký tự tối đa có thể được đọc trong một lần trên một thiết bị đầu cuối được xác định bởi N_TTY_BUF_SIZEtrong nguồn kernel. Các giá trị là 4096.

Đây là một hạn chế của giao diện đầu cuối, cụ thể là chế độ chính tắc (đã nấu chín) cung cấp trình chỉnh sửa dòng cực kỳ thô sơ (backspace, enter, Ctrl+ Dở đầu dòng cho cuối tập tin). Nó xảy ra hoàn toàn bên ngoài quá trình đọc.

Bạn có thể chuyển thiết bị đầu cuối sang chế độ thô, vô hiệu hóa xử lý dòng. Nó cũng vô hiệu hóa Ctrl+ Dvà các niceties khác, tạo thêm gánh nặng cho chương trình của bạn.

Đây là một giới hạn Unix cổ đại chưa bao giờ được sửa chữa vì có ít động lực. Con người không nhập những hàng dài như vậy. Nếu bạn đang cho đầu vào từ một chương trình, bạn sẽ chuyển hướng đầu vào của chương trình từ một tệp hoặc một đường ống.

Ví dụ: để sử dụng nội dung của bảng tạm X, đường ống từ xselhoặc xclip. Trong trường hợp của bạn:

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

Xóa -bhoặc -selection clipboardsử dụng lựa chọn X (tùy chọn được đặt bằng cách tô sáng bằng chuột) thay vì bảng tạm.

Trên OSX, sử dụng pbpasteđể dán nội dung clipboard (và pbcopyđể đặt nó).

Bạn có thể truy cập bảng tạm X qua SSH nếu bạn kích hoạt chuyển tiếp X11 với ssh -X(điều mà một số máy chủ có thể cấm). Nếu bạn chỉ có thể sử dụng sshmà không cần chuyển tiếp X11, bạn có thể sử dụng scp, sftphoặc sshfssao chép một tập tin.

Nếu dán là giải pháp duy nhất bởi vì bạn không thể chuyển tiếp bảng tạm hoặc bạn không dán nhưng ví dụ giả mạo nhập vào máy ảo, một cách tiếp cận khác là mã hóa dữ liệu vào một thứ có dòng mới. Base64 rất phù hợp cho việc này: nó biến đổi dữ liệu tùy ý thành các ký tự có thể in và bỏ qua khoảng trắng khi giải mã. Cách tiếp cận này có lợi thế bổ sung là nó hỗ trợ dữ liệu tùy ý trong đầu vào, thậm chí kiểm soát các ký tự mà thiết bị đầu cuối sẽ giải thích khi dán. Trong trường hợp của bạn, bạn có thể mã hóa nội dung:

xsel -b | base64 | xsel -b

sau đó giải mã nó:

cơ sở64 -d
 Paste
Ctrl+D

Lưu ý rằng có một lỗi tham nhũng dữ liệu thực sự khó chịu khi sử dụng xselvới> 4k byte: github.com/kfish/xsel/issues/14
Patrick

14

Giới hạn bạn đang chạy là kích thước tối đa của một dòng trong chế độ đầu vào chính tắc , MAX_CANON.

Trong chế độ đầu vào chính tắc, trình điều khiển tty cung cấp các dịch vụ chỉnh sửa dòng cơ bản để chương trình không gian người dùng không cần. Nó không có nhiều tính năng như readline, nhưng nó nhận ra một vài ký tự đặc biệt có thể định cấu hình như xóa (thường là Backspace hoặc Xóa) và giết (thường là Ctrl-U).

Quan trọng nhất đối với câu hỏi của bạn, chế độ đệm chuẩn cho đầu vào cho đến khi nhìn thấy ký tự cuối dòng. Bởi vì bộ đệm nằm trong trình điều khiển tty, trong bộ nhớ kernel, nó không lớn lắm.

Bạn có thể tắt chế độ chính tắc bằng stty cbreakhoặc stty -icanon, sau đó thực hiện dán. Điều này có nhược điểm đáng kể là bạn sẽ không thể gửi EOF bằng Ctrl-D. Đó là một trong những điều mà chế độ kinh điển chịu trách nhiệm. Bạn vẫn có thể chấm dứt catbằng Ctrl-C vì các ký tự tạo tín hiệu được điều khiển bởi một cờ riêng ( stty rawhoặc stty -isig).

Điều bí ẩn đối với tôi là tại sao, vì bạn đã chứng minh rằng bạn biết về nó xclip, bạn không chỉ sử dụng xclip -o > filethay vìcat


1
Bí ẩn có thể dễ dàng giải quyết: Có vẻ như artfulrobot muốn nhanh chóng điền vào một tệp trên một máy chủ từ xa với dữ liệu từ bảng ghi tạm. Trong shell từ xa, thông thường không có quyền truy cập trực tiếp vào clipboard tạm thời thông qua xclip.
jofel

3
Ah, tốt tải lên cũ bằng cách dán. Nếu tôi phải làm một trong những điều đó và nó không phải là văn bản đơn giản, tôi sẽ viết nó thay vì cố gắng thuyết phục người lái xe tty vượt qua nó. Văn bản đơn giản với các dòng lớn cũng có thể được xử lý theo cách đó.

2

Nếu bạn làm:

stty eol =

Và sau đó chạy bản demo được đề xuất trong EDIT của bạn , bạn sẽ thấy thanh foo trong bản in của test.out . Kỷ luật dòng của thiết bị đầu cuối sẽ chuyển đầu ra của nó tới đầu đọc của nó khi nó đọc từng ký tự eol đặc biệt trong đầu vào của bạn.

Thiết bị đầu cuối chế độ chính tắc Linux - có thể được cấu hình bằng stty icanonhoặc có thể chỉ stty sane- xử lý các ký tự đầu vào đặc biệt sau ...

  • điện tử
    • mặc định: ^D
    • Chấm dứt một dòng đầu vào và tuôn ra đầu ra cho đầu đọc. Bởi vì nó được xóa khỏi đầu vào, nếu nó là đầu vào dưới dạng ký tự duy nhất trên một dòng, nó được truyền dưới dạng null đọc - hoặc cuối tệp - cho người đọc.
  • eol
    • mặc định: chưa gán
    • Cũng chấm dứt một dòng đầu vào, nhưng không bị xóa khỏi đầu vào.
  • giết chết
    • mặc định: ^U
    • Xóa tất cả các đầu vào đệm.
  • xóa
    • mặc định: ^H (hoặc có thể @hoặc ^?trên một số hệ thống)
    • Xóa ký tự đầu vào được đệm cuối cùng.

Khi iexten cũng được thiết lập - như stty icanon iextenhoặc, một lần nữa, có lẽ chỉ là stty sane, một thiết bị đầu cuối Linux chuẩn cũng sẽ xử lý ...

  • eol2
    • mặc định: chưa gán
    • Ngoài ra cũng chấm dứt một dòng đầu vào, và cũng không được loại bỏ từ đầu vào.
  • người sói
    • mặc định: ^W
    • Xóa từ đầu vào được đệm cuối cùng .
  • rprnt
    • mặc định: ^R
    • In lại tất cả các đầu vào đệm.
  • văn bản
    • mặc định: ^V
    • Loại bỏ bất kỳ ý nghĩa đặc biệt nào liên quan đến kỷ luật dòng đối với ký tự đầu vào ngay sau đây.

Các ký tự này được xử lý bằng cách xóa chúng khỏi luồng đầu vào - ngoại trừ eoleol2 , nghĩa là - và thực hiện chức năng đặc biệt được liên kết trước khi truyền luồng đã xử lý đến đầu đọc - thường là vỏ của bạn, nhưng có thể là bất kỳ nhóm quy trình tiền cảnh nào .

Các ký tự đầu vào đặc biệt khác được xử lý tương tự nhưng có thể được cấu hình độc lập với bất kỳ cài đặt icanon nào bao gồm tập isig - set like stty isigvà có lẽ cũng được bao gồm trong cấu hình lành mạnh :

  • bỏ
    • mặc định: ^\
    • Xóa tất cả đầu vào được đệm (nếu noflsh không được đặt) và gửi SIGQUIT đến nhóm quy trình tiền cảnh - có khả năng tạo ra kết xuất lõi.
  • nghi ngờ
    • mặc định: ^Z
    • Xóa tất cả đầu vào được đệm (nếu noflsh không được đặt) và gửi SIGTSTP đến nhóm quy trình tiền cảnh. Nhóm quy trình bị đình chỉ có thể được nối lại với một trong kill -CONT "$!"hoặc chỉ fgtrong một vỏ ( set -m) được kiểm soát công việc.
  • xâm nhập
    • mặc định: ^C
    • Xóa tất cả đầu vào được đệm (nếu noflsh không được đặt) và gửi SIGINT đến nhóm quy trình tiền cảnh.

Và bộ ixon - được định cấu hình như stty ixonvà cũng thường được bao gồm trong cấu hình sane :

  • dừng lại
    • mặc định: ^S
    • Dừng tất cả đầu ra cho đầu đọc cho đến khi bắt đầu được đọc trong đầu vào hoặc - khi ixany cũng được đặt - ít nhất một ký tự nữa được đọc.
  • khởi đầu
    • mặc định: ^Q
    • Khởi động lại đầu ra nếu trước đó đã bị dừng với dừng .
  • Cả dừngbắt đầu đều bị xóa khỏi đầu vào khi được xử lý, nhưng nếu đầu ra được khởi động lại do bất kỳ ký tự nào trong đầu vào khi ixany được đặt thì ký tự đó sẽ không bị xóa.

Các ký tự đặc biệt được xử lý trên các hệ thống không phải Linux khác có thể bao gồm ...

  • tuôn ra
    • mặc định: ^O
    • Tách bỏ và loại bỏ đầu vào đệm và được loại bỏ khỏi đầu vào.
  • dusp
    • mặc định: chưa gán
    • Xóa tất cả đầu vào được đệm chỉ khi người đọc đọc ký tự đầu vào đặc biệt được gán sau đó gửi SIGTSTP.

Và có thể...

  • swtch
    • mặc định ^@ (có nghĩa là \0hay NUL)
    • Chuyển lớp tiền cảnh lớp vỏ. Để sử dụng với ứng dụng shl lớp vỏ trên một số hệ thống.
    • Việc triển khai shlnhiều ptys và do đó tương thích với kiểm soát công việc thay vì hành vi phụ thuộc swtch của triển khai ban đầu có thể được tự do có trong bộ heirloom-toolchestcông cụ.

Để có một bức tranh rõ ràng hơn về cách thức và lý do (và có lẽ tại sao không) các chức năng đầu vào này được xử lý tham khảo ý kiến man 3 termios.

Tất cả các chức năng trên có thể được chỉ định (hoặc được chỉ định lại) - khi áp dụng - như thế nào sttyfunction assigned-key. Để vô hiệu hóa bất kỳ chức năng duy nhất làm . Ngoài ra, như những nỗ lực khác nhau với nhiệm cho bất kỳ chức năng line-chỉnh sửa nói trên với tất cả các GNU, AST, hoặc gia truyền của hiện thực dường như chỉ ra, bạn cũng có thể như NUL nhượng cho bất kỳ chức năng dường như tương đương với thiết lập nó để unassigned trên linux của tôi hệ thống.sttyfunction^-sttysttyfunction^@

Có thể bạn thấy tiếng vang của các ký tự này khi bạn nhập chúng (như có thể được định cấu hình w / [-] ctlecho ) , nhưng đây chỉ là một điểm đánh dấu để cho bạn biết bạn đã làm gì - chương trình nhận đầu vào của bạn không có ý kiến ​​gì về bạn đã gõ chúng (ngoại trừ eol [2] , nghĩa là) và chỉ nhận được một bản sao đầu vào của bạn mà kỷ luật dòng đã áp dụng hiệu ứng của chúng.

Hậu quả của việc xử lý các chức năng chỉnh sửa dòng khác nhau của thiết bị đầu cuối là nó phải cần bộ đệm đầu vào ở một mức độ nào đó để hành động theo các chức năng mà bạn chỉ ra rằng nó nên - và do đó không thể có nguồn cung cấp đầu vào vô hạn có lẽ bạn bất cứ lúc nào giết . Bộ đệm dòng chính xác hơn là bộ đệm kill .

Nếu bạn đặt các ký tự eol hoặc eol2 thành một số dấu phân cách xuất hiện trong đầu vào - ví dụ ngay cả khi đó không phải là một dòng mới hoặc ký tự trả về - thì bạn sẽ chỉ có thể giết đến điểm xảy ra lần cuối và bộ đệm giết của bạn sẽ mở rộng hết mức có thể cho đến khi tiếp theo trong số này - hoặc một dòng mới (hoặc trả về nếu icrnl được đặt và igncr không) - xảy ra trong đầu vào.


1

catsẽ chấp nhận bất kỳ số lượng ký tự nào, như bạn có thể chứng kiến ​​bằng cách làm ví dụ cat /dev/random > test.bin(không làm điều đó trừ khi bạn biết cách ngăn chặn nó :). Tôi đã thử sao chép và dán một tập tin lớn vào cat > test.txt. Tất cả các dòng kết thúc trong tệp cho dù tôi đã hủy bằng Ctrl- choặc Ctrl- d, nhưng trong trường hợp trước, không phải tất cả các dòng được in đến thiết bị đầu cuối . Điều này tôi tin là bởi vì catbộ đệm của nó in, chờ đợi một bộ đệm hoàn chỉnh của văn bản hoặc nhập trực tiếp từ thiết bị đầu cuối trước mỗi lần in.

Trên hệ thống của tôi, tôi nghĩ kích thước bộ đệm là 4096 (2 ^ 12) byte: Tạo một tệp 4095 byte bằng cách sử dụng (printf '1234567890%.0s' {1..409} && printf 12345) > test.in, tải tệp đó vào bộ đệm sao chép bằng cách sử dụng xclip test.in, bắt đầu cat > test.out, dán bằng cách sử dụng Shift- Insertvà chấm dứt luồng bằng cách nhấn Ctrl- d. Bây giờ thêm một byte bằng cách sử dụng printf '6' >> test.invà luồng được in hai lần : Một lần trong catđầu ra (tất cả 4096 byte) và 4095 byte cuối cùng một lần nữa trên vỏ sau khi kết thúc.


+1 Trong trường hợp của tôi, nó cũng phụ thuộc vào bảng tạm được sử dụng. Nếu tôi đã sử dụng bộ đệm lựa chọn (dán giữa nhấp) tôi chỉ thấy 4542 dòng dữ liệu thử nghiệm đầu tiên của mình (nhưng tất cả chúng đều nằm trong tệp đã tạo) nhưng sử dụng bảng tạm X (Ctrl + C / Ctrl + V) tôi đã thấy tất cả. Trong cả hai trường hợp, tất cả dữ liệu được in vào tệp kết quả nhưng trước đây chỉ có một phần dữ liệu được hiển thị trong thiết bị đầu cuối.
terdon

1
Tôi không có hành vi tương tự. Xem câu hỏi đã được chỉnh sửa
artfulrobot

0

Một giải pháp là dán nó vào một trình soạn thảo hỗ trợ các dòng dài, ví dụ như vim.

Nếu bạn sử dụng vim, trước tiên hãy nhập chế độ dán với :pastetrước khi vào chế độ chèn với ivà dán văn bản.

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.