Enter tuşu neden EOL göndermiyor?


19

Unix / Linux EOL, LF, hat besleme, ASCII 10, kaçış dizisidir \n.

Tam olarak bir tuşa basmak için bir Python snippet'i:

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

Ben bastığınızda Enterbu pasajı cevaben benim klavyede, o verir \r, satır başı, ASCII 13.

On Windows'un , Entergönderir CR LF == 13 10. * nix Windows değildir; neden Enter10 yerine 13 veriyor?


İki bayt okumayı deneyin .
Michael Hampton

@MichaelHampton Hayır, bir bayt okunduktan sonra bu dosya tanımlayıcısında bekleyen hiçbir şey yok
cat

Yanıtlar:


11

İken Thomas Dickey'nin cevabı oldukça doğrudur, Stéphane Chazelas doğru dönüşüm dokunulmaz olmadığını Dickey'nin cevabı Bir yorumda; hat disiplininin bir parçasıdır.

Aslında çeviri tamamen programlanabilir.

Adam 3 termios adam sayfası temelde tüm ilgili bilgileri içerir. (Bağlantı, hangi özelliklerin yalnızca Linux'ta olduğunu ve POSIX veya diğer sistemlerde ortak olan Linux man- page projesini alır ; her zaman oradaki her sayfadaki Uygunluk bölümünü kontrol edin .)

iflag(Terminal nitelikler old_settings[0]söz konusu gösterilen kod Python ) Tüm POSIXy sistemlerinde üç alakalı bayrakları vardır:

  • INLCR: Ayarlanmışsa, NL'yi girişte CR'ye çevirin
  • ICRNL: Ayarlanmışsa (ve IGNCRayarlanmadıysa), girişte CR'yi NL'ye çevirin
  • IGNCR: Girişte CR'yi yoksay

Benzer şekilde, ilgili çıktı ayarları ( old_settings[1]) da vardır:

  • OPOST: Çıktı işlemeyi etkinleştir.
  • OCRNL: Çıktıda CR'yi NL ile eşleştirin.
  • ONLCR: NL'yi çıktıda CR ile eşleştirin. (XSI; tüm POSIX veya Single-Unix-Specification sistemlerinde mevcut değildir.)
  • ONOCR: İlk sütundaki CR'yi atlayın (çıktı vermeyin).
  • ONLRET: Atla (çıkış yok) CR.

Örneğin, ttymodüle güvenmekten kaçınabilirsiniz . "Makeraw" işlemi sadece bir takım bayrakları temizler (ve oflag'ı ayarlar CS8):

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

uyumluluk uğruna, öncelikle tüm bu sabitlerin termios modülünde olup olmadığını kontrol etmek isteyebilirsiniz (POSIX olmayan sistemlerde çalıştırıyorsanız). Ayrıca kullanabilirsiniz new_settings[6][termios.VMIN]ve new_settings[6][termios.VTIME]orada hiçbir bekleyen bir veridir ve ne kadar süre (deciseconds tamsayı sayısında) eğer sete salt bloke edip. (Tipik VMINolarak 0'a ve VTIMEokumaların hemen dönmesi gerekiyorsa veya okumanın en fazla ne kadar bekleyeceği pozitif bir sayıya (saniye onda) ayarlanır .)

Gördüğünüz gibi, yukarıdaki (ve genel olarak "makeraw") girişteki tüm çeviriyi devre dışı bırakır, bu da kedinin gördüğü davranışı açıklar:

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

Normal davranışlar elde etmek için, bu üç satırı temizleyen satırları atlamanız yeterlidir ve "ham" olduğunda bile giriş çevirisi değişmez.

new_settings[1] = new_settings[1] & ~termios.OPOSTHat tüm çıkış işleme devre dışı bırakır, başka çıkış bayrakları demek ne olursa olsun. Çıktı işlemeyi sağlam tutmak için atlayabilirsiniz. Bu ham modda bile çıkışı "normal" tutar. (Girişin otomatik olarak yankılanıp ECHOyanılmadığını etkilemez; bu cflag tarafından kontrol edilir new_settings[3].)

Son olarak, yeni özellikler ayarlandığında, yeni ayarlardan herhangi biri yapılmışsa çağrı başarılı olur . Ayarlar hassassa (örneğin, komut satırında bir şifre istiyorsanız), yeni ayarları almalı ve emin olmak için önemli bayrakların doğru ayarlandığını / ayarlandığını doğrulamalısınız.

Mevcut terminal ayarlarınızı görmek istiyorsanız,

stty -a

Giriş bayrakları genellikle dördüncü satırda ve çıkış bayrakları beşinci satırda, -bayrak ayarlanmamışsa bayrak adından önce gelir. Örneğin, çıktı

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

Psödoterminallerde ve USB TTY cihazlarında, baud hızı önemsizdir.

Parolaları okumak isteyen Bash komut dosyaları yazarsanız, aşağıdaki deyimi göz önünde bulundurun:

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

EXITKabuk çıkan her tuzak yürütülür. stty -gGeçerli ayarlar zaman komut dosyası çıkışlar, otomatik olarak geri yüklenir böylece, yazılı kaydın başlangıcında terminali geçerli ayarlarını okur. Senaryoyu Ctrl+ ile kesebilirsin Cve doğru olanı yapar. (Sinyallerle bazı köşe durumlarda, ben terminali bazen yazmak için birini gerektiren ham / kuralsız ayarlarla (tıkıldım aldığını tespit ettik reset+ Enter) terminali de körlemesine, ama motor stty sanegerçek orijinal ayarları geri yüklemeden önce her zaman için bunu ortadan kaldırıncaya Bu yüzden orada, bir çeşit ek güvenlik.)

readDahili bash kullanarak giriş satırlarını (terminale bağlı olmayan) okuyabilir, hatta giriş karakterlerini karakter bazında okuyabilirsiniz

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

IFSASCII NUL olarak ayarlamazsanız , readyerleşik ayırıcılar tüketir, böylece bu cboş olur. Genç oyuncular için tuzak.


1
Ah, tanrıların uğruna, hiçbir şey olduğu hiç :( basit
kedi

Bu cevabı kabul ediyorum, çünkü diğeri harika olsa bile bana bir Python dev olarak yardımcı oluyor
kedi

2
@cat: Bu sizin için en yararlı olsa da, yine de Thomas Dickey'in cevabının daha doğru olduğunu söyleyebilirim . Onun yerine bunu kabul etmeyi tercih ederim.
Nominal Hayvan

4
+15 temsilcinizden vazgeçme isteğiniz size kredi verirken, @cat oldukça haklıdır. Bir yanıtın kabul edilip edilmemesi, gönderilen cevapların "en doğru" olduğuna dair bir gösterge değildir. Bu sadece OP'nin kişisel nedenlerden ötürü tercih ettiği anlamına gelir. "En doğru" genellikle en çok oylananlardır. Bir yanıtı kabul etmek kişisel tercihinize bağlıdır, eğer OP sizinkini tercih ederse, kabul etmemek için bir neden yoktur.
terdon

1
@terdon: Tamam, düzeltilmiş duruyorum.
Nominal Hayvan

30

Esasen "çünkü manuel daktilolardan beri böyle yapıldı". Gerçekten mi.

Manuel daktiloda kağıdın beslendiği bir taşıyıcı vardı ve siz yazarken ileriye doğru ilerlediler (bir yay yükleme) ve yayı taşıyıcıyı sol kenar boşluğuna döndürmesine izin veren bir kolu veya anahtarı vardı.

Elektronik veri girişi (teletype, vb.) Tanıtıldıkça, bunu ileri taşıdılar. Bu yüzden Enterbirçok terminaldeki anahtar etiketlenir Return.

Taşıyıcı sol kenar boşluğuna döndürüldükten sonra satır beslemeleri (manuel işlemde) oldu. Yine, elektronik cihazlar manuel cihazları taklit ederek ayrı bir line-feedişlem gerçekleştirdi.

Her iki işlem de kodlanır (teletipin kağıt türü oluşturan bağımsız bir cihazdan daha fazla olmasına izin vermek için), bu nedenle CR(satır başı) ve LF(satır besleme) var. ASR 33 Teletype Bilgileri'nden bu görüntü , klavyeyi Returnsağ tarafta ve Line-Feedhemen solda gösterir. Sağda olmak , ana anahtardı:

resim açıklamasını buraya girin

Unix daha sonra geldi. Geliştiricileri bir şeyleri kısaltmayı severdi ( creat"oluşturmak" için bile tüm kısaltmalara bakın ). Muhtemelen iki bölümden oluşan bir süreçle karşı karşıya kaldıklarında, satır beslemelerinin yalnızca satır başlarından önce gelmeleri durumunda mantıklı olduğuna karar verdiler. Böylece dosyalardan açık satır başı döndürdüler Returnve karşılık gelen satır beslemesini göndermek için terminalin anahtarını çevirdiler. Sadece karışıklığı önlemek için satır beslemeye "satırsonu" adını verdiler.

Terminalde metin yazarken, Unix diğer yöne çevrilir: satır besleme satır başı / satır besleme olur.

(Yani "normalde": çeviri yapılmayan "ham" modun aksine "pişmiş mod" olarak adlandırılır).

Özet:

  • satır başı / satır besleme 13 13 dizisidir
  • Cihaz ( "sonsuza dek" senin açısından beri) 13 gönderir
  • Unix benzeri sistemler bunu 13 10 olarak değiştirir
  • Diğer sistemlerin sadece 10 depolaması gerekmez (Windows, uyumluluğun ne kadar önemli olduğuna bağlı olarak sadece 10 veya 13 10'u kabul eder).

1
Manuel daktilo için kolları göstermek için güzel bir resim aradım, ancak yalnızca düşük çözünürlüklü görüntüler buldum.
Thomas Dickey

3
Bunlardan birini yazmak zorunda olsaydınız, her şeyi kısaltırsınız!
Michael Hampton

3
Tarih kısmı ilgili olarak: Ben kullanımda kullanılan manuel daktilo, benzer bu bir tek kolu vardı. Çektiğinizde, önce silindiri (hat besleme) krankladı ve sonra sadece taşıyıcıyı çekti. Ve yayı bu çeken şeydi. Yazılan her harf veya sekme basıldığında, yay bir şekilde serbest bırakılır, şaryo, başlangıcında değil satırın sonunda olan "yüksüz" konuma geri getirilir.
RealSkeptic

2
Girişte, CR (Lty hattı disiplini ile) CR LF'ye değil, LF'ye çevrilir. LF Çevrilen çıktıdadır (girdinin yankısı dahil) CR LF. foo<Return>Pişmiş moda yazdığınızda , uygulama okur foo\nve foo\r\nyankı için hat disiplini terminale gönderilir.
Stéphane Chazelas

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.