आप एक फाइल से जुड़े स्टडआउट के साथ एक टर्मिनल बना रहे हैं ताकि सामान्य इको-बैक टर्मिनलों को स्क्रीन के बजाय फ़ाइल में भेजा जा रहा हो।
इम सुनिश्चित करें कि spawn
इस तरह सीधे इस्तेमाल किया जा करने का इरादा है नहीं: pty
पुस्तकालय pty.fork()
प्रदान करता है एक बच्चे प्रक्रिया बनाने के लिए और stdin/stdout के लिए एक फ़ाइल वर्णनकर्ता देता है। लेकिन इसका उपयोग करने के लिए आपको बहुत अधिक कोड की आवश्यकता होगी।
वर्तमान समस्या आप spawn
साथ कर रहे हैं को दूर करने, यहाँ दो आसान विकल्प:
विकल्प 1: तुम सब के बारे में फाइल करने के लिए पैदा की कमान के उत्पादन में भेज रहा है परवाह है, तो आप कर सकते हैं
जो इस तरह दिखेगा चलते हैं तो:
start to stdout only
hello
complete to stdout only
(मैं अजगर के लिए पाइप और
here
फ़ाइलें एक-लाइनर्स नामित पसंद करते हैं) 210
जो दिखाता है कि इनपुट (मैंने हैलो टाइप किया है) और प्रिंट स्टेटमेंट का परिणाम स्क्रीन पर जा रहा है। Out.txt की सामग्री होगी:
$ cat out.txt
hello
यही है, जो आपने टाइप किया है।
विकल्प 2: दूसरी ओर तुम बाहर फ़ाइल चाहते तो पैदा की कमान उत्पादन के आसपास अजगर उत्पादन को रोकने के लिए है, तो आप कुछ में थोड़ा और अधिक जटिल है, जैसे की जरूरत है:
python <(cat << EOF
import sys
import pty
import os
old_stdout = sys.stdout
sys.stdout = myfdout = os.fdopen(4,"w")
print 'start to out file only'
myfdout.flush()
pty.spawn(sys.argv[1:])
print 'complete to out file only'
sys.stdout = old_stdout
EOF
) bash -c 'cat >&4' 4>out.txt
जो होगा बाहर फ़ाइल में शामिल होंगे
hello
लेकिन:
0 केवल टर्मिनल जब चलाने (यानी जो कुछ भी आप टाइप) को यह उत्पादन
पृष्ठभूमि: अजगर pty
पुस्तकालय शक्तिशाली है: इसकी एक टर्मिनल अजगर प्रक्रियाओं stdout और stdin से जुड़ी उपकरण बनाने। आईडी कल्पना करें कि इसका अधिकांश उपयोग pty.fork()
कॉल का उपयोग करेगा ताकि वास्तविक stdin/stdout प्रभावित न हों।
हालांकि आपके मामले में, आपके खोल पर, आपने पाइथन प्रक्रिया के stdout को एक फ़ाइल में रीडायरेक्ट किया। इसके परिणामस्वरूप पीटीआई को भी फाइल से जुड़ा हुआ था, इसलिए स्टडिन पर स्टडीन को प्रतिबिंबित करने की सामान्य कार्रवाई को रीडायरेक्ट किया जा रहा था। नियमित स्टडआउट (स्क्रीन) अभी भी जगह पर था लेकिन नई पीटीआई द्वारा इसका उपयोग नहीं किया जा रहा था।
विकल्प 1 ऊपर के लिए मुख्य अंतर के लिए, pty.spawn
कॉल के अंदर कहीं न कहीं होने की stdout के पुनर्निर्देशन स्थानांतरित करने के लिए जब यह गूंज की कोशिश करता है ताकि प्राइवेट बनाया अभी भी वास्तविक टर्मिनल stdout के लिए एक स्पष्ट संबंध नहीं है (है stdin आप टाइप के रूप में)
विकल्प 2 के लिए अंतर एक मनमाना फ़ाइल वर्णनकर्ता पर एक दूसरे चैनल (यानी फ़ाइल वर्णनकर्ता 4) बना सकते हैं और stdout के स्थान पर इस का उपयोग करने के लिए, एक बार आप अजगर के अंदर हैं और जब आप बनाते हैं आपकी तैयार प्रक्रिया (यानी आपकी स्पॉन्ड प्रक्रिया के stdout को उसी फ़ाइल डिस्क्रिप्टर पर रीडायरेक्ट करें)
इनमें से दोनों अंतर पीटीआई को रोकते हैं कि pty.spawn
वास्तविक टर्मिनल से अपना स्टडआउट बदल या डिस्कनेक्ट होने से बनाता है। यह stdin की echo-back ठीक से काम करने की अनुमति देता है।
संकुल कि pty
पुस्तकालय का उपयोग करें और आप अधिक नियंत्रण दे रहे हैं, लेकिन आप इनमें से अधिकांश pty.fork()
का उपयोग करें (और दिलचस्प बात मैंने पाया नहीं किया अभी तक है कि वास्तव में pty.spawn
उपयोग करता है)
संपादित यहाँ एक उदाहरण है मिल जाएगा
import sys
import pty
import os
import select
import time
import tty
import termios
print 'start'
try:
pid, fd = pty.fork()
print 'forked'
except OSError as e:
print e
if pid == pty.CHILD:
cmd = sys.argv[1]
args = sys.argv[1:]
print cmd, args
os.execvp(cmd,args)
else:
tty.setraw(fd, termios.TCSANOW)
try:
child_file = os.fdopen(fd,'rw')
read_list = [sys.stdin, child_file]
while read_list:
ready = select.select(read_list, [], [], 0.1)[0]
if not ready and len(read_list) < 2:
break
elif not ready:
time.sleep(1)
else:
for file in ready:
try:
line = file.readline()
except IOError as e:
print "Ignoring: ", e
line = None
if not line:
read_list.remove(file)
else:
if file == sys.stdin:
os.write(fd,line)
else:
print "from child:", line
except KeyboardInterrupt:
pass
संपादित यह questionpty.fork()
के लिए कुछ अच्छे संबंध हैं: pty.fork() का उपयोग करने का
अद्यतन: कोड में कुछ टिप्पणियां करने चाहिए थे कैसे pty.fork()
उदाहरण काम करता है:
interpretor pty.fork()
करने के लिए कॉल निष्पादित करता है, processesing दो में विभाजित हो: वहाँ अब दो धागे कि दोनों प्रतीत होती हैं अभी pty.fork()
कॉल निष्पादित किया है।
एक धागा वह धागा है जो आप मूल रूप से (माता-पिता) में थे और एक नया धागा (बच्चा) है।
माता-पिता में, pid
और fd
बच्चे की प्रक्रिया आईडी और एक फाइल decriptor तेह बच्चे की stdin और stdout में connnected की तैयारी में हैं:, माता पिता में जब आप fd
आप पढ़ रहे हैं क्या करने के लिए लिखा गया है से पढ़ा बच्चे stdout; जब आप fd
पर लिखते हैं तो आप बच्चों के स्टडीन को लिख रहे हैं। तो अब, माता-पिता में हमारे पास अन्य धागे के साथ अपने stdout/stdin पर संचार करने का एक तरीका है।
बच्चे में, pid
0 पर सेट किया गया है और fd
सेट नहीं है। अगर हम पैरेंट थ्रेड से बात करना चाहते हैं, तो हम यह जानकर stdin/stdout पर पढ़ और लिख सकते हैं कि माता-पिता इसके साथ कुछ कर सकते हैं और करना चाहिए।
दो धागे इस बिंदु से एक ही कोड निष्पादित करने जा रहे हैं, लेकिन हम बता सकते हैं कि हम pid
में मान के आधार पर माता-पिता या बच्चे धागे में हैं या नहीं। अगर हम बच्चे और अभिभावक धागे में अलग-अलग चीजें करना चाहते हैं तो हमें केवल एक सशर्त बयान की आवश्यकता है जो बच्चे को एक कोड पथ और माता-पिता को एक अलग कोड पथ से नीचे भेजता है। Thats क्या इस लाइन करता है:
if pid == pty.CHILD:
#child thread will execute this code
....
else
#parent thread will execute this code
...
बच्चे में, हम बस एक नया Pty में नए आदेश अंडे देने के लिए चाहते हैं। os.execvp
प्रयोग किया जाता है क्योंकि हम इस विधि के साथ, लेकिन अनिवार्य रूप से इसकी/stdout ही pty.spawn()'. This means the child stdin/stdout are now connected to the command you wanted via a pty. IMmportantly, any input or output from the command (or the pty for that matter) will be available to the parent thread by reading from
रूप fd . And the parent can write to the command via pty by writing to
fd`
तो अब, माता पिता में, हम वास्तविक stdin कनेक्ट करने के लिए जरूरत है एक टर्मिनल के रूप में Pty पर अधिक नियंत्रण होगा fd
पर पढ़ने और लिखने के माध्यम से बच्चे stdin/stdout के लिए। यह है कि अब मूल कोड क्या करता है (else
भाग)। असली स्टडीन पर चालू होने वाला कोई भी डेटा fd
पर लिखा गया है। fd
(अभिभावक द्वारा) से पढ़े गए किसी भी डेटा को stdout पर लिखा गया है। तो माता-पिता का धागा अब एकमात्र चीज है जो असली स्टडीन/स्टडआउट और एफडी के बीच प्रॉक्सी कर रहा है। यदि आप प्रोग्रामिंग के कमांड के इनपुट और आउटपुट के साथ कुछ करना चाहते हैं, तो यह वह जगह है जहां आप इसे करेंगे।
tty.setraw(fd, termios.TCSANOW)
यह एक तरीका है गूंज वापस कर रोकने के लिए बच्चे में Pty बताने के लिए है:
केवल दूसरी बात यह है कि माता-पिता में क्या होता है इस कॉल है।
यह समस्या आप मूल रूप से कर रहे थे हल करती है: - अपने स्थानीय टर्मिनल केवल माता-पिता धागा से जुड़ा है - सामान्य गूंज वापस जगह में है (यानी पहले अपने इनपुट प्रक्रिया में पारित हो जाता) - की stdout प्रक्रिया पुनः निर्देशित किया जा सकता है - बच्चे की प्रक्रिया अपने stdin
कि तरह लगता है की स्थानीय गूंज वापस नहीं कर करने के लिए कहा गया है - जो आप अपने टर्मिनल stdout के साथ क्या बच्चे प्रक्रिया की stdin/stdout पर कोई प्रभाव नहीं पड़ता बहुत स्पष्टीकरण - अगर किसी के पास स्पष्टता के लिए कोई संपादन है?
समाधान विकल्प 1 और विकल्प 2 बाहरी पायथन प्रक्रिया (यानी जो अन्य प्रोग्राम कहता है/स्पॉन करता है) के लिए मेरे लिए काम नहीं करता है, 'stdout' को फ़ाइल/पाइप पर रीडायरेक्ट किया जाता है, और यह मेरे नियंत्रण में नहीं है (क्योंकि इसे किसी और द्वारा इस तरह से बुलाया जाता है; मेरे पास केवल मेरे नियंत्रण में पाइथन लिपि चलती है)। इसलिए मैं आंतरिक प्रक्रिया में रीडायरेक्ट आउटपुट को चुन और स्थानांतरित नहीं कर सकता। (लेकिन हाँ अगर मेरे पास वह स्वतंत्रता थी तो विकल्प 1 और 2 स्वीकार्य होगा) –
मैंने अंतिम उदाहरण कोड (** EDIT ** में) चलाया और ऐसा लगता है कि वास्तव में मेरी समस्या का समाधान होता है। लेकिन मैं अभी भी अपने सिर को लपेटने के लिए संघर्ष कर रहा हूं कि यह वास्तव में कैसे काम करता है :( –
@ अभिषेक-केडिया Ive ने एक व्याख्या जोड़ा – spacepickle