Enter कुंजी ईओएल क्यों नहीं भेजती है?


19

यूनिक्स / लिनक्स ईओएल एलएफ, लाइनफीड, एएससीआईआई 10, एस्केप सीक्वेंस है \n

यहां एक पायथन स्निपेट है जो वास्तव में एक कुंजी पाने के लिए है:

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इस स्निपेट के जवाब में अपने कीबोर्ड पर प्रेस करता हूं, तो यह \rASCII 13 देता है।

पर विंडोज , Enterभेजता है CR LF == 13 10। * निक्स विंडोज नहीं है; Enter10 के बजाय 13 क्यों देता है ?


दो बाइट्स पढ़ने की कोशिश करें ।
माइकल हैम्पटन

@Michael Hampton नोप, एक बाइट को पढ़ने के बाद उस फाइल डिस्क्रिप्टर पर कुछ भी इंतजार नहीं होता है
बिल्ली

जवाबों:


11

जबकि थॉमस डिक्की का उत्तर काफी सही है, स्टीफन चेज़ेलस ने डिके के जवाब के लिए एक टिप्पणी में सही उल्लेख किया है कि रूपांतरण पत्थर में सेट नहीं है; यह लाइन अनुशासन का हिस्सा है।

वास्तव में, अनुवाद पूरी तरह से प्रोग्राम योग्य है।

आदमी 3 termios आदमी पेज मूल रूप से सभी प्रासंगिक जानकारी शामिल है। (लिंक लिनक्स मैन-पेज प्रोजेक्ट पर ले जाता है , जो उल्लेख करता है कि कौन सी सुविधाएँ केवल लिनक्स हैं, और जो पीओएस या अन्य प्रणालियों के लिए आम हैं; हमेशा प्रत्येक पृष्ठ पर अनुभाग के अनुरूप होने की जाँच करें ।)

iflagटर्मिनल विशेषताएं ( old_settings[0]में सवाल में दिखाया गया कोड में अजगर ) सभी POSIXy सिस्टम पर तीन प्रासंगिक झंडे है:

  • INLCR: यदि सेट है, तो इनपुट पर NL से CR का अनुवाद करें
  • ICRNL: यदि सेट (और IGNCRसेट नहीं है), इनपुट पर सीआर को एनएल में अनुवाद करें
  • IGNCR: इनपुट पर सीआर को अनदेखा करें

इसी तरह, संबंधित आउटपुट सेटिंग्स ( old_settings[1]) भी हैं:

  • OPOST: आउटपुट प्रोसेसिंग सक्षम करें।
  • OCRNL: आउटपुट पर मानचित्र सीआर से एनएल।
  • ONLCR: आउटपुट पर NL से CR का मैप। (XSI; सभी POSIX या एकल-यूनिक्स-विनिर्देश प्रणालियों में उपलब्ध नहीं है।)
  • ONOCR: पहले कॉलम में छोड़ें (आउटपुट न करें) सीआर।
  • ONLRET: छोड़ें (आउटपुट न करें) सीआर।

उदाहरण के लिए, आप ttyमॉड्यूल पर भरोसा करने से बच सकते हैं । "मेकरव" ऑपरेशन सिर्फ झंडे का एक सेट साफ करता है (और 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

हालांकि अनुकूलता के लिए, आप यह जांचना चाहेंगे कि क्या उन सभी स्थिरांक पहले टर्मिनस मॉड्यूल में मौजूद हैं (यदि आप गैर-पॉसिक्स सिस्टम पर चलते हैं)। आप यह भी उपयोग कर सकते हैं new_settings[6][termios.VMIN]और new_settings[6][termios.VTIME]यह निर्धारित करने के लिए कि क्या कोई पेंडिंग डेटा नहीं है, और कितनी देर तक रुकेगा (और पूर्णांक के पूर्णांक संख्या में)। (आमतौर पर VMIN0 पर सेट किया जाता है, औरVTIME 0 पर अगर रीड को तुरंत वापस लौटना चाहिए, या एक पॉजिटिव नंबर पर (सेकंड का दसवां हिस्सा) कितनी देर तक रीड को सबसे ज्यादा इंतजार करना चाहिए।)

जैसा कि आप देख सकते हैं, ऊपर (और "निर्माता" सामान्य रूप से) इनपुट पर सभी अनुवाद को निष्क्रिय कर देता है, जो बताता है कि व्यवहार बिल्ली देख रही है:

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

सामान्य व्यवहार प्राप्त करने के लिए, बस उन तीन पंक्तियों को साफ़ करने वाली लाइनों को छोड़ दें, और "कच्चे" होने पर भी इनपुट अनुवाद अपरिवर्तित है।

new_settings[1] = new_settings[1] & ~termios.OPOSTलाइन सभी उत्पादन प्रसंस्करण अक्षम करता है, भले ही क्या अन्य उत्पादन झंडे का कहना है। आप इसे केवल आउटपुट प्रोसेसिंग को अक्षुण्ण रखने के लिए छोड़ सकते हैं। यह कच्चे मोड में भी आउटपुट "सामान्य" रखता है। (यह प्रभावित नहीं करता है कि इनपुट स्वचालित रूप से प्रतिध्वनित होता है या नहीं; यह ECHOcflag द्वारा नियंत्रित किया जाता है new_settings[3]।)

अंत में, जब नई विशेषताओं को सेट किया जाता है, तो कॉल सफल होगा यदि कोई हो नई सेटिंग सेट । यदि सेटिंग्स संवेदनशील हैं - उदाहरण के लिए, यदि आप कमांड लाइन पर एक पासवर्ड के लिए पूछ रहे हैं -, तो आपको नई सेटिंग्स प्राप्त करनी चाहिए, और यह सत्यापित करना चाहिए कि महत्वपूर्ण झंडे सही रूप से सेट / परेशान हैं, सुनिश्चित करने के लिए।

यदि आप अपनी वर्तमान टर्मिनल सेटिंग्स देखना चाहते हैं, तो दौड़ें

stty -a

इनपुट फ़्लैग आमतौर पर चौथी पंक्ति पर होते हैं, और -फ़्लैग नाम के पूर्ववर्ती ध्वज के साथ आउटपुट फ़्लैग होते हैं, यदि फ़्लैग का नाम अप्रकाशित हो। उदाहरण के लिए, आउटपुट हो सकता है

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, और यह सही काम करेगा। (संकेतों के साथ कुछ कोने के मामलों में, मैंने पाया है कि टर्मिनल कभी-कभी कच्ची / गैर-वैज्ञानिक सेटिंग्स ( टर्मिनल में टाइप reset+ ब्लाइंड के लिए एक की आवश्यकता होती है) के साथ फंस जाता है Enter, लेकिन stty saneवास्तविक मूल सेटिंग्स को पुनर्स्थापित करने से पहले चलने से यह ठीक हो जाता है कि हर बार मुझे। इसीलिए यह वहां है; एक प्रकार की अतिरिक्त सुरक्षा।)

आप readबिल्ट-इन का उपयोग करके इनपुट लाइनें (टर्मिनल से बाहर) पढ़ सकते हैं , या इनपुट चरित्र-दर-वर्ण का उपयोग करके भी पढ़ सकते हैं

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

यदि आप IFSASCII NUL पर सेट नहीं हैं , तो readअंतर्निहित विभाजक का उपभोग करेंगे, ताकि cखाली हो जाए। युवा खिलाड़ियों के लिए ट्रैप।


1
ओह, देवताओं के लिए, कुछ भी सरल नहीं है :(
बिल्ली

मैं इस जवाब को स्वीकार कर रहा हूं क्योंकि यह मेरे लिए सबसे ज्यादा मददगार है, जबकि पायथन देव के रूप में, भले ही दूसरा महान हो
बिल्ली

2
@ कोट: जबकि यह आपके लिए सबसे अधिक उपयोगी हो सकता है, मैं फिर भी कहूंगा कि थॉमस डिकी का उत्तर अधिक सही है । मैं आपको इसके बजाय स्वीकार करना चाहता हूं।
नाममात्र पशु

4
जबकि आपके +15 प्रतिनिधि को त्यागने की आपकी इच्छा आपको श्रेय देती है, @cat काफी सही है। एक उत्तर को स्वीकार किया जाता है या नहीं कोई संकेत नहीं है कि यह पोस्ट किए गए उत्तरों का "सबसे सही" है। इसका मतलब केवल यह है कि ओपी जो भी व्यक्तिगत कारणों से पसंद करता है। "सबसे सही" आमतौर पर सबसे उच्च उत्थान है। उत्तर स्वीकार करना व्यक्तिगत पसंद पर निर्भर है, अगर ओपी आपकी पसंद करता है, तो इसे स्वीकार नहीं करने का कोई कारण नहीं है।
terdon

1
@terdon: ठीक है, मैं सही है, तो खड़े हो जाओ।
नाममात्र पशु

30

अनिवार्य रूप से "क्योंकि यह मैन्युअल टाइपराइटर के बाद से इस तरह किया गया है"। वास्तव में।

एक मैनुअल टाइपराइटर में एक गाड़ी होती थी जिस पर कागज खिलाया जाता था, और जब आप टाइप करते थे (वसंत को लोड करते हुए) तो यह आगे बढ़ता था, और एक लीवर या चाबी होती थी जो गाड़ी को छोड़ देती थी, जिससे वसंत गाड़ी को बाएं-मार्जिन पर वापस आ जाता था।

जैसा कि इलेक्ट्रॉनिक डेटा प्रविष्टि (टेलेटाइप, आदि) पेश किए गए थे, उन्होंने इसे आगे बढ़ाया। इसलिए Enterकई टर्मिनलों की कुंजी लेबल की जाएगी Return

बाईं फ़ीड मार्जिन पर गाड़ी वापस करने के बाद लाइन फीड हुआ (मैन्युअल प्रक्रिया में)। फिर से, इलेक्ट्रॉनिक उपकरणों ने मैनुअल उपकरणों की नकल की, जिससे एक अलग line-feedऑपरेशन हुआ।

दोनों ऑपरेशन एन्कोडेड हैं (टेलेटाइप को एक पेपर प्रकार बनाने वाले स्टैंडअलोन डिवाइस से अधिक होने की अनुमति देने के लिए), इसलिए हमारे पास CR(गाड़ी-वापसी) और LF(लाइन-फीड) है। एएसआर 33 टेलेटाइप सूचना से यह छवि कीबोर्ड Returnको दाईं ओर, और Line-Feedबस बाईं ओर दिखाती है । दाईं ओर होने के कारण , यह मुख्य कुंजी थी:

यहाँ छवि विवरण दर्ज करें

बाद में यूनिक्स आया। इसके डेवलपर्स को चीजों को छोटा करना पसंद था (सभी संक्षिप्त रूपों को देखें, यहां तक creatकि "बनाएं")। संभवतः दो-भाग की प्रक्रिया का सामना करते हुए, उन्होंने फैसला किया कि लाइन-फीड केवल तभी समझ में आता है जब वे गाड़ी-रिटर्न से पहले थे। इसलिए उन्होंने फाइलों से स्पष्ट कैरिज रिटर्न को गिरा दिया , और Returnइसी लाइन-फीड को भेजने के लिए टर्मिनल की कुंजी का अनुवाद किया । बस भ्रम से बचने के लिए, उन्होंने "न्यूलाइन" के रूप में लाइन-फीड का उल्लेख किया।

टर्मिनल पर पाठ लिखते समय, यूनिक्स दूसरी दिशा में अनुवाद करता है: एक लाइन-फीड कैरिज-रिटर्न / लाइन-फीड बन जाता है।

(वह है, "सामान्य रूप से": तथाकथित "पकाया मोड", "कच्चे" मोड के विपरीत जहां कोई अनुवाद नहीं किया जाता है)।

सारांश:

  • गाड़ी-वापसी / लाइन-फीड क्रम १३ १० है
  • डिवाइस 13 भेजता है (के बाद से "हमेशा के लिए" अपने संदर्भ में)
  • यूनिक्स जैसी प्रणालियां बदलकर 13 10 हो जाती हैं
  • अन्य प्रणालियाँ आवश्यक रूप से सिर्फ 10 को स्टोर नहीं करती हैं (विंडोज काफी हद तक सिर्फ 10 या 13 10 को स्वीकार करता है, यह निर्भर करता है कि संगतता कितनी महत्वपूर्ण है)।

1
मैंने एक मैनुअल टाइपराइटर के लिए लीवर दिखाने के लिए एक अच्छी तस्वीर की तलाश की, लेकिन केवल कम रिज़ॉल्यूशन वाली तस्वीरें ही मिलीं।
थॉमस डिकी

3
यदि आपको उनमें से किसी एक पर लिखना है, तो आप सब कुछ संक्षिप्त कर देंगे!
माइकल हैम्पटन

3
इतिहास के हिस्से के बारे में: मैंने अपने उपयोग में जो मैनुअल टाइपराइटर इस्तेमाल किए हैं, उनमें से यह केवल एक लीवर के समान था। जब आप इसे खींचते हैं, तो यह पहले रोलर (लाइन फीड) को क्रैंक करता है और फिर यह सिर्फ गाड़ी को खींचता है। और यह वह पुल था जिसने वसंत को लोड किया था। प्रत्येक अक्षर टाइप किया गया, या टैब दबाया गया, वसंत को कुछ हद तक छोड़ देगा, गाड़ी को "अनलोड" स्थिति पर वापस ले जाएगा, जो कि लाइन के अंत में था, इसकी शुरुआत नहीं।
रियलसेप्टिक

2
इनपुट पर, CR का अनुवाद (Tty लाइन अनुशासन द्वारा) LF में किया जाता है, CR LF पर नहीं। यह आउटपुट पर है (इनपुट की गूंज सहित) जिसका LF अनुवाद किया गया है CR LF। जब आप foo<Return>पकाए गए मोड में टाइप करते हैं , तो एप्लिकेशन पढ़ता है foo\nऔर foo\r\nटर्मिनल पर गूंज के लिए लाइन अनुशासन द्वारा वापस भेजा जाता है।
स्टीफन चेजलस

हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.