एक प्रक्रिया की गति के लिए लेखन


10

जहाँ तक मैं समझता हूँ अगर मैं निम्नलिखित टाइप करता हूँ ...

 python -i

... अजगर-दुभाषिया अब स्टड से पढ़ेगा, इस तरह से व्यवहार करना (जाहिर है):

 >>> print "Hello"
 Hello

मुझे उम्मीद है कि अगर मैं ऐसा करता हूं तो वही काम करेगा:

 echo 'print "Hello"' > /proc/$(pidof python)/fd/0

लेकिन यह आउटपुट है (वास्तविक खाली लाइन को देखते हुए):

 >>> print "Hello"
 <empyline>

यह मेरे जैसा दिखता है, यह सिर्फ ले गया print "Hello"\nऔर इसे लिखा stdout, फिर भी इसकी व्याख्या नहीं की। वह काम क्यों नहीं कर रहा है और मुझे इसे काम करने के लिए क्या करना होगा?


TIOCSTI ioctl एक टर्मिनल के लिए लिख सकते हैं stdin के रूप में यदि डेटा कीबोर्ड से दर्ज किया गया है। उदाहरण के लिए github.com/thrig/scripts/blob/master/tty/ttywrite.c
रोइमा

जवाबों:


9

इस तरह से गोले / दुभाषियों के लिए इनपुट भेजना बहुत समस्याग्रस्त है और किसी भी विश्वसनीय तरीके से काम करना बहुत मुश्किल है।

उचित तरीका सॉकेट्स का उपयोग करना है, यही कारण है कि उनका आविष्कार किया गया था, आप कमांड लाइन का उपयोग करके ncat ncया socatएक साधारण सॉकेट में अजगर प्रक्रिया को बांधने के लिए कर सकते हैं । या एक साधारण अजगर आवेदन लिखें जो पोर्ट को बांधता है और एक सॉकेट पर व्याख्या करने के लिए आदेशों के लिए सुनता है।

सॉकेट स्थानीय हो सकते हैं और किसी भी वेब इंटरफ़ेस के संपर्क में नहीं आ सकते।


समस्या यह है कि यदि आप pythonकमांड लाइन से शुरू करते हैं, तो यह आमतौर पर आपके शेल से जुड़ा होता है जो टर्मिनल से जुड़ा होता है, वास्तव में हम देख सकते हैं

$ ls -al /proc/PID/fd
lrwxrwxrwx 1 USER GROUP 0 Aug 1 00:00 0 -> /dev/pty1

इसलिए जब आप stdinअजगर के बारे में लिखते हैं, तो आप वास्तव में ptyएक साधारण फ़ाइल नहीं, बल्कि psuedo- टर्मिनल, जो एक कर्नेल डिवाइस है, लिख रहे हैं । यह उपयोग ioctlनहीं करता है readऔर writeइसलिए, आपको अपनी स्क्रीन पर आउटपुट दिखाई देगा, लेकिन यह स्पैन्ड प्रक्रिया को नहीं भेजा जाएगा ( python)

आप जो कोशिश कर रहे हैं उसे दोहराने का एक तरीका है fifoया named pipe

# make pipe
$ mkfifo python_i.pipe
# start python interactive with pipe input
# Will print to pty output unless redirected
$ python -i < python_i.pipe &
# keep pipe open 
$ sleep infinity > python_i.pipe &
# interact with the interpreter
$ echo "print \"hello\"" >> python_i.pipe

आप screenकेवल इनपुट के लिए भी उपयोग कर सकते हैं

# start screen 
$ screen -dmS python python
# send command to input
$ screen -S python -X 'print \"hello\"'
# view output
$ screen -S python -x

यदि आप पाइप को खुला रखते हैं (जैसे sleep 300 > python_i.pipe &) दूसरी तरफ बंद नहीं pythonहोगा और पाइप के नीचे कमांड को स्वीकार करना जारी रखेगा। इसके द्वारा भेजे गए अनुसार कोई ईओएफ नहीं है echo
रोइमा

@roaima तुम सही हो, मुझे मेरी समझ में यह गलत लग रहा था कि धारा बंद होने पर ईओओ ईओएफ भेजता है। यह |पाइप के साथ परिहार्य नहीं है , हालांकि, सही है?
अर्धशतक

मैं पहले से ही पेंडो रोड से नीचे था, लेकिन echo something > fifoइससे एक ईओएफ मिलेगा, जो कई अनुप्रयोगों को रोक देगा। sleep infinity > fifoवैकल्पिक हल हालांकि मेरे मध्य पार नहीं किया, धन्यवाद!
6

1
वास्तव में अपने विचार को जारी रखते हुए, आप ऐसा भी कर सकते हैं python -i <> fifoजो EOF
Sheppy

11

पहुँच PID प्रक्रिया के फ़ाइल डिस्क्रिप्टर 0 तक नहीं पहुँचती है , यह उस फाइल तक पहुँचता है जिसे PID ने फाइल डिस्क्रिप्टर 0. पर खोला है। यह एक सूक्ष्म अंतर है, लेकिन यह मायने रखता है। एक फाइल डिस्क्रिप्टर एक कनेक्शन है जो एक प्रक्रिया में एक फ़ाइल है। फ़ाइल डिस्क्रिप्टर पर लिखना फ़ाइल को इस बात की परवाह किए बिना लिखता है कि फ़ाइल को कैसे खोला गया है।/proc/PID/fd/0

यदि एक नियमित फ़ाइल है, तो इसे लिखना फ़ाइल को संशोधित करता है। डेटा जरूरी नहीं है कि प्रक्रिया आगे क्या पढ़ेगी: यह फ़ाइल डिस्क्रिप्टर से जुड़ी स्थिति पर निर्भर करता है कि प्रक्रिया फ़ाइल को पढ़ने के लिए उपयोग कर रही है। जब कोई प्रक्रिया खुलती है , तो उसे अन्य प्रक्रिया के समान फ़ाइल मिलती है, लेकिन फ़ाइल स्थिति स्वतंत्र होती है।/proc/PID/fd/0/proc/PID/fd/0

यदि एक पाइप है, तो इसे लिखना पाइप के बफर में डेटा को जोड़ता है। उस स्थिति में, पाइप से पढ़ने वाली प्रक्रिया डेटा को पढ़ेगी।/proc/PID/fd/0

यदि एक टर्मिनल है, तो इसे लिखना टर्मिनल पर डेटा को आउटपुट करता है। एक टर्मिनल फ़ाइल द्विदिश है: इसे लिखना डेटा को आउटपुट करता है, अर्थात टर्मिनल टेक्स्ट प्रदर्शित करता है; एक टर्मिनल इनपुट से रीडिंग, यानी टर्मिनल उपयोगकर्ता इनपुट प्रसारित करता है।/proc/PID/fd/0

पायथन टर्मिनल के लिए पढ़ना और लिखना दोनों है। जब आप दौड़ते हैं echo 'print "Hello"' > /proc/$(pidof python)/fd/0, तो आप print "Hello"टर्मिनल को लिख रहे होते हैं। print "Hello"निर्देशानुसार टर्मिनल प्रदर्शित करता है । अजगर प्रक्रिया में कुछ भी नहीं दिखता है, यह अभी भी इनपुट की प्रतीक्षा कर रहा है।

यदि आप पायथन प्रक्रिया को इनपुट फीड करना चाहते हैं, तो आपको इसे करने के लिए टर्मिनल प्राप्त करना होगा। ऐसा करने के तरीकों के लिए crasic का उत्तर देखें ।


2

गाइल्स ने जो कहा , उसका निर्माण करते हुए , यदि हम एक प्रक्रिया के स्टैडेन को लिखना चाहते हैं जो एक टर्मिनल से जुड़ा हुआ है, तो हमें वास्तव में टर्मिनल को जानकारी भेजने की आवश्यकता है। हालाँकि, क्योंकि एक टर्मिनल इनपुट के रूप में और साथ ही आउटपुट के रूप में कार्य करता है, जब इसे लिखना टर्मिनल के पास यह जानने का कोई तरीका नहीं है कि आप "स्क्रीन" के बजाय इसके भीतर चल रही प्रक्रिया को लिखना चाहते हैं।

लेकिन लिनक्स में एक ioctl अनुरोध के माध्यम से उपयोगकर्ता इनपुट का अनुकरण करने का एक गैर-पॉज़िक्स तरीका है TIOCSTI(टर्मिनल I / O नियंत्रण - सिम्यूलेट टर्मिनल इनपुट) जो हमें टर्मिनल द्वारा पात्रों को भेजने की अनुमति देता है जैसे कि वे उपयोगकर्ता द्वारा टाइप किए गए थे।

मैं केवल सतही रूप से जानता हूं कि यह कैसे काम करता है, लेकिन इस जवाब के आधार पर , यह संभव होना चाहिए कि कुछ लाइनों के साथ ऐसा करना चाहिए

import fcntl, sys, termios

tty_path = sys.argv[1]

with open(tty_path, 'wb') as tty_fd:
    for line in sys.stdin.buffer:
        for byte in line:
            fcntl.ioctl(tty_fd, termios.TIOCSTI, bytes([byte]))

कुछ बाहरी संसाधन:

http://man7.org/linux/man-pages/man2/ioctl.2.html

http://man7.org/linux/man-pages/man2/ioctl_tty.2.html


निरीक्षण करें कि यह प्रश्न किसी विशेष ऑपरेटिंग सिस्टम के लिए विशिष्ट नहीं है, और यह कि TIOCSTI लिनक्स के साथ उत्पन्न नहीं हुआ था। इस उत्तर के लिखे जाने से लगभग दो साल पहले, लोगों ने सुरक्षा कारणों से TIOCSTI को छोड़ना शुरू कर दिया था। unix.stackexchange.com/q/406690/5132
JdeBP

@JdeBP इसलिए मेरा निर्दिष्ट "लिनक्स" (हालांकि मुझे यकीन नहीं है कि यह कहां से उत्पन्न हुआ है)। और "लोगों" द्वारा, ऐसा लगता है कि आपको कुछ बीएसडी का मतलब है? जब मैंने यह लिखा था तब से जो मैंने पढ़ा है, उससे ऐसा लगता है कि एक बहुत पुराने कार्यान्वयन में, एक सुरक्षा जोखिम जो बाद में पैच किया गया है, लेकिन बीएसडी ने अभी भी पूरी तरह से ioctl को गिराने के लिए इसे "सुरक्षित" समझ लिया है। लेकिन मैं इस बारे में किसी भी तरह से बहुत अपरिचित हूं, इसलिए मुझे लगा कि यह कहना बेहतर नहीं है कि कुछ प्रणालियों पर कुछ संभव नहीं था जब मुझे उस प्रणाली का कोई अनुभव नहीं है।
क्रिश्चियन रियलल-फ्लर्टी
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.