端末で改行せずに4k入力を読み取る方法は?


25

そのため、クリップボードには新しい行のない大量のデータがあります(1行の大きなSVGファイルです)。私は行った

$ cat >file.svg

(Gnomeターミナルで)貼り付けようとしましたが、最初の4kB文字のみが受け入れられました。

これはreadlineの機能/制限だと思います。

この問題を回避する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です。


SVGファイルがクリップボードに完全に読み込まれましたか?
lgeorget

あなたの実際の問題は何ですか?クリップボードの内容をファイルに保存する方法は?その場合、ターミナルに貼り付ける以外の方法があります。
lgeorget

あなたの場合、Nはいくらですか?私は2kBのxmlデータ(LFを含む)で問題なく試しました。
fduff

1
@artfulrobotフォアグラウンドプロセスは、tty / ptyと直接対話します。シェルは関係ありません。プログラムでreadlineまたは他の入力ライブラリ自体を使用しない場合、readline機能(コマンドの編集/ジャンプ、履歴など)がないため、これを見ることができます。
ジョフェル

1
これはreadlineの制限ではありません。readlineとbashはここでは関係しません。これは、端末インターフェイスの制限です。
ジル「SO-悪であるのをやめる」

回答:


22

Linuxでソースを正しく理解している場合、端末で一度に読み取れる最大文字数はN_TTY_BUF_SIZE、カーネルソースによって決定されます。値は 4096です。

これは、ターミナルインターフェースの制限です。特に、非常に粗雑な行エディター(バックスペース、エンター、ファイルの終わりの行の先頭で+ を提供する標準(「調理済み」)モードです。読み取り中のプロセスの完全に外部で発生します。CtrlD

端末をrawモードに切り替えて、回線処理を無効にすることができます。また、Ctrl+ Dなどの機能が無効になり、プログラムに余分な負荷がかかります。

これは古代のUnixの制限であり、動機がほとんどないため修正されることはありません。人間はそのような長い列には入らない。プログラムから入力を供給している場合は、ファイルまたはパイプからプログラムの入力をリダイレクトします。

たとえば、Xクリップボードのコンテンツを使用するには、xselまたはからパイプしxclipます。あなたの場合:

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

クリップボードではなく、X選択(マウスで強調表示することによって設定されるもの)を削除する-b-selection clipboard、使用します。

OSXでは、を使用pbpasteしてクリップボードのコンテンツを貼り付けます(およびpbcopy設定します)。

X11転送を有効にすると、SSH経由でXクリップボードにアクセスできますssh -X(一部のサーバーでは禁止されています)。sshX11転送なしでのみ使用できる場合はscpsftpまたはsshfsを使用してファイルをコピーできます。

クリップボードを転送できないため、貼り付けだけが解決策である場合、または貼り付けではなく仮想マシンへの入力を偽装している場合、別のアプローチはデータを改行のあるものにエンコードすることです。Base64はこれに最適です。任意のデータを印刷可能な文字に変換し、デコード時に空白を無視します。この方法には、入力時に任意のデータをサポートするという追加の利点があり、貼り付け時に端末が解釈する制御文字もサポートされます。あなたの場合、コンテンツをエンコードできます:

xsel -b | base64 | xsel -b

それをデコードします:

base64 -d
 Paste
Ctrl+D

xsel4kバイト以上で使用すると、非常に厄介なデータ破損バグがあることに注意してください:github.com/kfish/xsel/issues/14
パトリック

14

実行している制限は、標準入力モードでの行の最大サイズですMAX_CANON

標準入力モードでは、ttyドライバーは基本的な行編集サービスを提供するため、ユーザースペースプログラムは必要ありません。readlineほど多くの機能はありませんが、erase(通常はBackspaceまたはDelete)やkill(通常はCtrl-U)などの構成可能な特殊文字をいくつか認識します。

あなたの質問にとって最も重要なことは、標準モードは行末文字が見えるまで入力をバッファリングすることです。バッファーはカーネルメモリーのttyドライバーにあるため、それほど大きくありません。

stty cbreakまたはstty -icanonで標準モードをオフにしてから、貼り付けを行うことができます。これには、Ctrl-DでEOFを送信できないという重大な欠点があります。これは、標準モードが担当するもう1つのことです。catシグナル生成文字は別のフラグ(stty rawまたはstty -isig)によって制御されるため、Ctrl-Cで終了できます。

私の謎は、なぜあなたが知っていることをすでに実証しているのでxclipxclip -o > file代わりにcat


1
この謎は簡単に解決できます。artfulrobotは、リモートホスト上のファイルをクリップボードのデータですばやく埋めたいと考えているようです。リモートシェルでは、通常、xclipを介してローカルクリップボードに直接アクセスすることはできません。
ジョフェル

3
ああ、昔ながらのアップロードによるアップロード。それらのいずれかを実行する必要があり、それがプレーンテキストではなかった場合、ttyドライバーにパススルーさせるように説得するのではなく、uuencodeします。巨大な線のあるプレーンテキストも同様に処理できます。

2

もしあなたがそうするなら:

stty eol =

そして、自分の中で提案され、デモ実行EDITを、次のように表示されますFOOバーをプリントアウトしてtest.outに。端末の回線制御は、入力内の各特別なeol文字を読み取るときに、その出力をリーダーにフラッシュします。

Linuxの標準モード端末-で設定できるstty icanonか、おそらくは単にstty sane-次の特別な入力文字を処理します...

  • eof
    • デフォルト: ^D
    • 入力行を終了し、出力をリーダーにフラッシュします。入力から削除されるため、行の唯一の文字として入力された場合、null読み取り(またはファイルの終わり)としてリーダーに渡されます
  • えろ
    • デフォルト:未割り当て
    • 入力行も終了しますが、入力から削除されません。
  • 殺します
    • デフォルト: ^U
    • バッファされた入力をすべて消去します。
  • 消す
    • デフォルト:(^H または場合によって@または^?一部のシステム)
    • 最後にバッファリングされた入力文字を消去します。

ときIEXTENがも設定されている-と同様stty icanon iextenか、もう一度、おそらくstty sane、標準的なLinuxのターミナルも処理します...

  • eol2
    • デフォルト:未割り当て
    • また、入力行終了し、入力から削除されません。
  • わせ
    • デフォルト: ^W
    • 最後にバッファリングされた入力ワードを消去します。
  • rprnt
    • デフォルト: ^R
    • バッファリングされたすべての入力を再印刷します。
  • lnext
    • デフォルト: ^V
    • 行規則が直後の入力文字に関する限り、特別な意味を削除します。

除く-これらの文字は、入力ストリームからそれらを除去することにより、処理されEOLeol2あり、 -そして読者に加工ストリームを渡す前に、関連する特別な機能を実行する-通常あなたのシェルですが、フォアグラウンドプロセスグループが何であれかもしれません。

同様に処理されるが、任意の独立に設定することができ、他の特殊入力文字ICANONの設定が含まISIGセット-のように設定stty isigし、おそらくに含ま正気の構成を:

  • 終了する
    • デフォルト: ^\
    • バッファされたすべての入力をフラッシュしnoflshが設定されていない場合)、SIGQUITをフォアグラウンドプロセスグループに送信します-おそらくコアダンプを生成します。
  • サスペ
    • デフォルト: ^Z
    • バッファされた入力をすべてフラッシュしnoflshが設定されていない場合)、SIGTSTPをフォアグラウンドプロセスグループに送信します。中断されたプロセスグループは、ジョブ制御シェルのいずれかkill -CONT "$!"またはfgで再開できます。set -m
  • intr
    • デフォルト: ^C
    • バッファされた入力をすべてフラッシュしnoflshが設定されていない場合)、SIGINTをフォアグラウンドプロセスグループに送信します。

そして、IXONのセット-のように構成stty ixonしても通常に含ま正気の設定:

  • やめる
    • デフォルト: ^S
    • 入力でstartが読み取られるか、またはixanyも設定されている場合、少なくとも1つ以上の文字が読み取られるまで、リーダーへのすべての出力を停止します。
  • 開始
    • デフォルト: ^Q
    • 以前にstop停止された出力を再開します。
  • 処理時に停止開始の両方が入力から削除されますが、ixanyが設定されているときに入力の文字が原因で出力が再開された場合、その文字は削除されません。

他の非Linuxシステムで処理される特殊文字には、次のものが含まれます。

  • 流す
    • デフォルト: ^O
    • バッファリングされた入力の破棄とフラッシュを切り替え、入力から削除します。
  • dsusp
    • デフォルト:未割り当て
    • リーダーが割り当てられた特殊入力文字を読み取り、SIGTSTPを送信した場合にのみ、すべてのバッファリングされた入力をフラッシュします。

そしておそらく...

  • あれ
    • デフォルト^@ \0またはを意味するNUL
    • 前景のシェルレイヤーを切り替えます。一部のシステムでshl シェルレイヤーアプリケーションで使用するため。
    • 実装shl多重化のptyとするジョブ制御ではなく、元の実装のと互換性を持つようになりSWTCH依存挙動は自由であったことができheirloom-toolchestツールスイート。

これらの入力関数がどのように、そしてなぜ(そしておそらくなぜそうではないか)処理されるより明確な画像については、を参照してくださいman 3 termios

上記のすべての機能は、該当する場合に割り当てることができます(または再割り当て)sttyfunction assigned-key。単一の機能を無効にするには、を実行します。また、様々なGNUのすべてと、前述の行編集機能のいずれかの割り当てと試み、AST、または家宝のような実装を示しているように見える、あなたもできるようNULのいずれかの機能の割り当ては、それを設定するに等しいように思わ割り当てられていない私のLinux上でシステム。sttyfunction^-sttysttyfunction^@

おそらく、あなたが見る行うエコーあなたがそれらを入力し、これらの文字のを(おそらくワット/設定することができるよう- ctlecho [] が、これは唯一のあなたがやったところをお見せするためのマーカーである-プログラムは、あなたの入力を受信すると、その概念はありませんそれらをタイプ(除くEOL [2]であるが、)およびライン規律がその効果を適用しているにご入力の唯一のコピーを受け取ります。

端末がさまざまな行編集機能を処理する結果、入力する必要があると指示した機能を実行するために、入力をある程度バッファリングする必要があります。したがって、無限の入力を行うことはできません。あなたはいつでも殺すかもしれません。ラインバッファは、より正確であるキルバッファ。

入力で発生する区切り文字にeolまたはeol2文字を設定すると(たとえば、どちらも改行文字でもリターン文字でもない場合)、最後に発生したポイントとキルバッファまでしかキルできません。または改行-これらの次まで限り、それはできる限り延長する(場合はリターンICRNLが設定され、IGNCRがされていない) -入力で起こります。


1

catあなたは例えばあなたが目撃することができるように、任意の数の文字を受け入れますcat /dev/random > test.bin(あなたがそれを止める方法を知らない限り、それをしないでください:)。大きなファイルをにコピーして貼り付けみましたcat > test.txtCtrl- 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と、ストリームが2回cat出力されます。出力に1 (すべて4096バイト)、終了後にシェルに最後の4095バイトが再度出力れます。


+1私の場合、使用するクリップボードにも依存していました。選択バッファーを使用した場合(中央クリックペースト)、テストデータの最初の4542行しか表示されませんでした(ただし、すべてが作成されたファイルになりました)が、Xクリップボード(Ctrl + C / Ctrl + V)を使用しましたそれのすべて。どちらの場合も、すべてのデータは結果ファイルに出力されましたが、前者では部分的なデータのみが端末に表示されました。
テルドン

1
私は同じ振る舞いをしません。編集された質問を見る
artfulrobot

0

1つの解決策は、vimなどの長い行をサポートするエディターに貼り付けることです。

vimを使用する場合は、まず:pasteinsert-modeを入力してからinsert-modeをi入力してテキストを貼り付けます。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.