2015-12-26 8 views
5

मैं लिनक्स पर एक साधारण खोल बनाने पर अपना सर्वश्रेष्ठ प्रयास कर रहा हूं। बस बुनियादी प्रणाली कॉल का उपयोग करने के तरीके को सीखने के लिए मैं कुछ बना सकता हूं।लिनक्स पर उपयोगकर्ता इनपुट से निपटने

परिदृश्य: आदेश में उपयोगकर्ता प्रकार, प्रेस टैब (ताकि खोल अपने आदेश स्वत: पूर्ण करता है), स्वत: पूर्ण आदेश बाहर पॉप (या सुझाव), उपयोगकर्ता प्रेस दर्ज करें, आदेश evals और कार्यान्वित ।

बस बैश की तरह।

मुझे पता चला है कि कैसे evals बनाने के लिए, आदेश टोकन में परिवर्तित करें, इसे पाइप और सामान के साथ निष्पादित करें। जो मैं समझ नहीं सकता वह इनपुट हिस्सा है। अर्थात् उन टैब कीस्ट्रोक।

मैं जानता हूँ कि मैं क्या विकल्प हैं:

  • getc() - अलग से हर किरदार मिलता है एक बफर में संग्रहीत। टैब कीस्ट्रोक कैसे प्राप्त करें, यह पता नहीं लगा सकता है, क्योंकि यह निष्पादन रोकता है जब तक कि यह '\ n' या Ctrl + D दिखाई देता है। किंडा महंगा है, क्योंकि कमांड में प्रत्येक चरित्र के लिए 1 getc() होगा। इसके अलावा, मुझे बफर रीयलोकेशन, अमूर्तकरण ... बू ...
  • scanf("%s") - बफर ओवरफ़्लो के बारे में बहुत चिंताजनक होगा। मैं उन टैब कीस्ट्रोक नहीं प्राप्त कर सकता हूं। निष्पादन रोकता है
  • read() (unistd.h से) - ऐसा कुछ हो सकता है जो मैं नहीं कर सकता। लेकिन मैंने यहां लोगों को देखा है जिन्होंने कहा कि यह करने के लिए इसका उपयोग करने के लिए एक वास्तविक दर्द है। मैंने जाँचा। यह है।
  • getline() - टैब कीस्ट्रोक नहीं मिल सकता है।

मैंने यह देखने के लिए बैश स्रोत कोड में देखा, यह इनपुट के साथ कैसे व्यवहार करता है, और हे भगवान! इस एक साधारण चीज़ (input.c फ़ाइल) करने के लिए समर्पित कोड की 450 लाइनें हैं।

क्या इससे वास्तव में कोई आसान समाधान नहीं है? मैं ncurses का उपयोग नहीं करना चाहता, मुझे पोर्टेबिलिटी की परवाह नहीं है, मैं सिर्फ एक लक्ष्य प्राप्त नहीं करना चाहता: उपयोगकर्ता इनपुट प्राप्त करना और टैब कुंजी दबाते समय जानना। जितना संभव हो उतना कम प्रयास के साथ, इसे सुंदर ढंग से करें।

+1

'if (fgetc (stdin) == '\ t') {// launch}' –

+0

@self: निष्पादन रोकता है। "लॉन्च" भाग केवल एंटर दबाए जाने के बाद ही निष्पादित होता है। प्रवेश करने से पहले मुझे इस चरित्र को प्राप्त करने की आवश्यकता है, इसलिए मैं इनपुट स्ट्रीम में पहले से लिखे गए कार्यों के लिए स्वत: पूर्णता कर सकता हूं। –

+0

इसे 'for (;;)' लूप में उपयोग करें, एक बार जब आप \ n' अन्य सभी इनपुट –

उत्तर

4

कुछ विशिष्ट ऑटो-पूर्णता प्राप्त करने के लिए, आप GNU readline लाइब्रेरी का उपयोग कर सकते हैं, जिसका उपयोग bash द्वारा किया जाता है।

यदि आप टर्मिनल पूर्ण स्क्रीन I/O (à la vi या emacs) पर ध्यान देते हैं तो GNU ncurses पर विचार करें।

टर्मिनल काफी जटिल और आर्केन चीजें हैं (क्योंकि वे पिछली शताब्दी से अजीब भौतिक टेलीलेट्स का अनुकरण करना चाहते हैं)। अक्सर, टीटी के line discipline के लिए कर्नेल में कुछ लाइन प्रोसेसिंग की जाती है। tty demystified वेबपृष्ठ पढ़ें। इसलिए, निम्न स्तर के कार्यों à la termios(3) उपयोग करने के लिए आर्केन हैं, और आपको readline या ncurses जैसे पुस्तकालयों को प्राथमिकता देना चाहिए।

तो, नहीं, टर्मिनल I/O के लिए स्वत: पूर्णता के लिए सरल समाधान नहीं हैं, क्योंकि ttys जटिल सामान हैं। भी tty(4) & tty_ioctl(4) & pty(7)

तुम भी strace(1) इस्तेमाल कर सकते हैं देखें समझने के लिए सभी जटिल system calls उदा द्वारा किया एक इंटरेक्टिव खोल

यह भी देखें this & that उत्तर।

+0

आप इस फ़ंक्शन के लिए स्रोत कोड को निश्चित रूप से समझ सकते हैं कि टर्मिनल के साथ आपकी आवश्यकताओं के अनुरूप कैसे बातचीत करें। – chqrlie

+0

वास्तव में gnu bash ऐसा करने के लिए gnu readline का उपयोग करता है। – Jasen

+0

मैं इसके लिए बाहरी पुस्तकालय का उपयोग कर सकता हूं, लेकिन अब यह दूसरी जगह पर है जब "पर्याप्त सुरुचिपूर्ण" होने की बात आती है। मैंने पाया कि यह काम करेगा, लेकिन अभी मैं @ chqrlie के जवाब की जांच नहीं करूँगा। यह बस और अधिक लगता है ... "शुद्ध" ... –

4

किसी भी देरी या बफरिंग के बिना टर्मिनल से व्यक्तिगत कीस्ट्रोक प्राप्त करने के लिए, आपको अपना मोड पकाया जाता है कच्चे से बदलना चाहिए। आप इसे फ़ंक्शन <termios.h> में परिभाषित फ़ंक्शन के साथ कर सकते हैं। विवरण के लिए मैन पेज देखें।

एक बार जब आप टर्मिनल को उचित मोड में सेट कर लेते हैं, तो टर्मिनल हैंडल से डेटा पढ़ने के लिए read() सिस्टम कॉल का उपयोग करना बुद्धिमानी है।

ध्यान रखें कि आपको उपयोगकर्ता इनपुट गूंजने के साथ सौदा करना होगा और यदि आप टैब विस्तार जैसे उन्नत सामान करना शुरू कर देते हैं, तो आपको अधिकांश लाइन संपादक को लागू करने की आवश्यकता होगी ... चरित्र संरचना और अन्य विषमताओं को संभालने का उल्लेख नहीं करना चाहिए टर्मिनल आपको मुफ्त में देता है। जैसा कि बेसिल कहते हैं, इसके लिए कोई आसान हस्तशिल्प समाधान नहीं है, लेकिन यह गड़बड़ में गोता लगाने के लिए बहुत ही निर्देशक होगा!

यदि आपको समय के लिए दबाया जाता है और यह एक असाइनेंट है, तो बस readline() का उपयोग करें और शेष शेल को पहले लागू करें। यह पहले से ही बहुत काम करेगा। यदि आप अभी भी हिम्मत करते हैं तो आप हमेशा बाद में वापस आ सकते हैं।

+0

मुझे अभी एहसास हुआ कि आपने अपने संपादन में क्या कहा है। हाँ, इसमें डाइविंग मजेदार है। और साथ ही, यह कुछ असाधारण रूप से बुनियादी है जो इसे छूता है "मुझे अपमानित करता है"। मुझे बेसिल के जवाब के साथ जाना होगा, क्योंकि जब कच्चे मोड की बात आती है तो मुझे अपने करियर पर सॉफ्टवेयर इंजीनियर के रूप में दूसरे विचार करना शुरू हो रहा है। और आत्महत्या भी। हालांकि मुझे किसी बिंदु पर challange पर वापस जाना होगा। –

+1

कोई अपराध नहीं ;-) इस निम्न स्तर की सामग्री में डिलिवरी प्याज पर छीलने जैसा लगता है: हर बार जब आपको लगता है कि आपको कोर मिल गया है, तो अप्रत्याशित फ्लफ की एक और परत खरोंच करने के लिए है, और इससे आप भी रोते हैं। – chqrlie

+1

आह, लेकिन 'termios.h' प्याज किसी भी अच्छे I/O पकवान में एक आवश्यक मसाला है। असुविधा को कम करने के लिए छीलते समय एक मोमबत्ती को हल्का करें, 'चयन' और 'स्विच' के चुटकी के साथ मिलाएं और एक अच्छा बुनियादी I/O हैंडलर एक घंटे से भी कम समय में बेक किया जा सकता है। एसओ में शायद एक अच्छी नुस्खा मिल सकती है। 'kbhit' खोजकर कुकबुक। आपको स्वाद में संशोधित करने की आवश्यकता होगी ... –

संबंधित मुद्दे