web-dev-qa-db-ja.com

EnterキーでEOLが送信されないのはなぜですか?

Unix/Linux EOLはLF、改行、ASCII 10、エスケープシーケンス\n

Python=のスニペットは、キープレスを1つだけ取得するためのものです。

import sys, tty, termios
fd = sys.stdin.fileno()
old_settings = termios.tcgetattr(fd)
try:
    tty.setraw(sys.stdin.fileno())
    ch = sys.stdin.read(1)
finally:
    termios.tcsetattr(fd, termios.TCSADRAIN, old_settings)
    return ch

押すと Enter このスニペットに応答して私のキーボードで、それは\r、キャリッジリターン、ASCII 13。

Windowsの場合 Enter 送信CR LF == 13 10。 * nixはWindowsではありません。どして Enter 10ではなく13を与える?

19
cat

Thomas Dickeyの回答 はかなり正しいですが、StéphaneChazelasはDickeyの回答へのコメントで、変換が正しく設定されていないことを正しく述べています。それはライン規律の一部です。

実際、翻訳は完全にプログラム可能です。

man 3 termios manページには、基本的にすべての関連情報が含まれています。 (リンクは Linux man-pages project を参照します。これは、Linux専用の機能、およびPOSIXまたは他のシステムに共通の機能に言及しています。常にを確認してください。各ページのセクションに準拠しています。)

iflag端末属性( Python の質問に示されているコードのold_settings[0])には、すべてのPOSIXyシステムで3つの関連するフラグがあります。

  • INLCR:設定されている場合、入力時にNLをCRに変換します
  • ICRNL:設定されている場合(およびIGNCRが設定されていない場合)、入力時にCRをNLに変換します
  • IGNCR:入力時にCRを無視します

同様に、関連する出力設定(old_settings[1])もあります。

  • OPOST:出力処理を有効にします。
  • OCRNL:出力時にCRをNLにマップします。
  • ONLCR:出力でNLをCRにマップします。 (XSI。すべてのPOSIXまたは単一UNIX仕様システムでは使用できません。)
  • ONOCR:最初の列のCRをスキップ(出力しない)します。
  • ONLRET:CRをスキップ(出力しない)。

たとえば、ttyモジュールに依存しないようにすることができます。 「makeraw」操作は、一連のフラグをクリアするだけです(そしてCS8 oflagを設定します)。

import sys
import termios

fd = sys.stdin.fileno()
old_settings = termios.tcgetattr(fd)
ch = None

try:
    new_settings = termios.tcgetattr(fd)
    new_settings[0] = new_settings[0] & ~termios.IGNBRK
    new_settings[0] = new_settings[0] & ~termios.BRKINT
    new_settings[0] = new_settings[0] & ~termios.PARMRK
    new_settings[0] = new_settings[0] & ~termios.ISTRIP
    new_settings[0] = new_settings[0] & ~termios.INLCR
    new_settings[0] = new_settings[0] & ~termios.IGNCR
    new_settings[0] = new_settings[0] & ~termios.ICRNL
    new_settings[0] = new_settings[0] & ~termios.IXON
    new_settings[1] = new_settings[1] & ~termios.OPOST
    new_settings[2] = new_settings[2] & ~termios.CSIZE
    new_settings[2] = new_settings[2] | termios.CS8
    new_settings[2] = new_settings[2] & ~termios.PARENB
    new_settings[3] = new_settings[3] & ~termios.ECHO
    new_settings[3] = new_settings[3] & ~termios.ECHONL
    new_settings[3] = new_settings[3] & ~termios.ICANON
    new_settings[3] = new_settings[3] & ~termios.ISIG
    new_settings[3] = new_settings[3] & ~termios.IEXTEN
    termios.tcsetattr(fd, termios.TCSANOW, new_settings)
finally:
    termios.tcsetattr(fd, termios.TCSADRAIN, old_settings)

return ch

ただし、互換性のために、これらのすべての定数がtermiosモジュールに存在するかどうかを最初に確認することもできます(非POSIXシステムで実行する場合)。 new_settings[6][termios.VMIN]new_settings[6][termios.VTIME]を使用して、保留中のデータがない場合に読み取りをブロックするかどうか、およびその時間(整数デシ秒単位)を設定することもできます。 (通常、VMINは0に設定され、読み取りをすぐに返す必要がある場合はVTIMEを0に設定します。または、読み取りが最大でどれだけ待機するかを正の数(1/10秒)に設定する必要があります。)

ご覧のとおり、上記(および一般に "makeraw")は、入力時のすべての変換を無効にします。これは、猫が見ている動作を説明しています。

    new_settings[0] = new_settings[0] & ~termios.INLCR
    new_settings[0] = new_settings[0] & ~termios.ICRNL
    new_settings[0] = new_settings[0] & ~termios.IGNCR

通常の動作を得るには、これらの3行をクリアする行を省略するだけで、「未加工」の場合でも入力変換は変更されません。

new_settings[1] = new_settings[1] & ~termios.OPOST行は、他の出力フラグの内容に関係なく、すべての出力処理を無効にします。省略して、出力処理をそのまま維持することができます。これにより、rawモードでも出力が「正常」に保たれます。 (入力が自動的にエコーされるかどうかには影響しません。これは、new_settings[3]ECHO cflagによって制御されます。)

最後に、新しい属性が設定されると、新しい設定のanyが設定されている場合、呼び出しは成功します。コマンドラインでパスワードを要求する場合など、設定が重要な場合は、新しい設定を取得し、重要なフラグが正しく設定/設定解除されていることを確認してください。

現在の端末設定を見たい場合は、

stty -a

通常、入力フラグは4行目にあり、出力フラグは5行目にあり、フラグが設定されていない場合は、フラグ名の前に-が付いています。たとえば、出力は次のようになります。

speed 38400 baud; rows 58; columns 205; line = 0;
intr = ^C; quit = ^\; erase = ^?; kill = ^U; eof = ^D; eol = M-^?; eol2 = M-^?; swtch = M-^?; start = ^Q; stop = ^S; susp = ^Z; rprnt = ^R; werase = ^W; lnext = ^V; flush = ^O; min = 1; time = 0;
-parenb -parodd cs8 hupcl -cstopb cread -clocal -crtscts
-ignbrk brkint -ignpar -parmrk -inpck -istrip -inlcr -igncr icrnl ixon -ixoff -iuclc ixany imaxbel iutf8
opost -olcuc -ocrnl onlcr -onocr -onlret -ofill -ofdel nl0 cr0 tab0 bs0 vt0 ff0
isig icanon iexten echo echoe echok -echonl -noflsh -xcase -tostop -echoprt echoctl echoke

疑似端末、およびUSB TTYデバイスでは、ボーレートは無関係です。

あなたが読みたいBashスクリプトを書いた場合パスワード、次のイディオムを検討してください:

#!/bin/bash
trap 'stty sane ; stty '"$(stty -g)" EXIT
stty -echo -echonl -imaxbel -isig -icanon min 1 time 0

EXITトラップは、シェルが終了するたびに実行されます。 stty -gは、スクリプトの開始時に端末の現在の設定を読み取るため、スクリプトが終了すると、現在の設定が自動的に復元されます。スクリプトを中断することもできます Ctrl+C、それは正しいことをします。 (シグナルのあるまれなケースでは、ターミナルがraw/noncanonical設定でスタックすることがあります(resetと入力する必要があります+ + Enter ターミナルで盲目的に)、しかし実際の元の設定を復元する前にstty saneを実行すると、毎回問題が解決しました。それがそこにある理由です。一種の追加された安全性。)

read bashビルトインを使用して、入力行(端末に選択されていない)を読み取ることができます。または、

IFS=$'\0'
input=""
while read -N 1 c ; do
    [[ "$c" == "" || "$c" == $'\n' || "$c" == $'\r' ]] && break
    input="$input$c"
done

IFSをASCII NULに設定しない場合、組み込みのreadは区切り文字を消費するため、cは空になります。若い選手のための罠。

11
Nominal Animal

本質的には「手動タイプライター以来、そのように行われているから」です。本当に。

手動タイプライターにはキャリッジがあり、その上に紙が送られ、タイプ(スプリングをロードする)と同時に前進し、レバーまたはキーがありましたキャリッジが解放され、スプリングがキャリッジを左マージンに戻します。

電子データ入力(テレタイプなど)が導入されたため、彼らはそれを進めました。だから Enter 多くの端末のキーにはラベルが付けられます Return

キャリッジを左マージンに戻した後、(手動プロセスで)ラインフィードが発生しました。繰り返しになりますが、電子デバイスは手動デバイスを模倣し、個別の line-feed 操作。

両方の操作はエンコードされているため(テレタイプをスタンドアロンデバイスよりも紙の種類を作成できるようにするため)、CR(キャリッジリターン)とLF(ラインフィード)があります。 ASR 33 Teletype Information からのこの画像は、右側にReturnが付いたキーボードを示し、Line-Feed左側にあります。 正しいにいるので、それが主なキーでした:

enter image description here

Unixは後で登場しました。その開発者は物事を短くすることを好みました(「[作成]の場合はcreatも含めて、すべての略語を見てください)。おそらく2つの部分からなるプロセスに直面して、改行は、改行が先行する場合にのみ意味があると判断しました。したがって、filesから明示的な改行を削除し、端末の Return 対応する改行を送信するキー。混乱を避けるために、彼らは改行を「改行」と呼んだ。

端末でテキストを書き込む場合、Unixは逆方向に変換します。ラインフィードはキャリッジリターン/ラインフィードになります。

(つまり、「通常」:変換が行われない「ロー」モードとは対照的に、いわゆる「クックドモード」)。

概要:

  • キャリッジリターン/ラインフィードはシーケンス13 10
  • deviceは13を送信します(用語では「永久に」以降)
  • Unixライクなシステムを13 10に変更
  • 他のシステムは必ずしも10のみを格納するわけではありません(Windowsは、互換性の重要性に応じて、10または13 10のみを受け入れます)。
30
Thomas Dickey