Süreç aşamasına yazma


10

Aşağıdakileri yazdığımda anladığım kadarıyla ...

 python -i

... python-tercüman şimdi (açıkça) şu şekilde davranarak stdin'den okuyacak:

 >>> print "Hello"
 Hello

Bunu yaparsam aynı şeyi yapmasını beklerim:

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

Ama bu çıktı (gerçek bir boş çizgi olmak):

 >>> print "Hello"
 <empyline>

Bu bana benziyor, sadece aldı print "Hello"\nve yazdı stdout, ancak yorumlamadı. Neden çalışmıyor ve çalışmasını sağlamak için ne yapmam gerekir?


TIOCSTI ioctl bir terminalin yazabilirsiniz Stdin veri klavyeden girildiğinde sanki. Örneğin github.com/thrig/scripts/blob/master/tty/ttywrite.c
roaima

Yanıtlar:


9

Kabuklara / tercümanlara bu şekilde girdi göndermek çok problemlidir ve güvenilir bir şekilde çalışmak çok zordur.

Uygun yol soketleri kullanmaktır, bu yüzden icat edildiler, bunu bir python işlemini kullanarak basit bir sokete bağlamak ncat ncveya socatbağlamak için komut satırında yapabilirsiniz . Veya bağlantı noktasına bağlanan ve bir soket üzerinde yorumlanacak komutları dinleyen basit bir python uygulaması yazın.

soketler yerel olabilir ve herhangi bir web arayüzüne maruz kalmayabilir.


Sorun şu ki python, komut satırından başlarsanız , genellikle bir terminale bağlı olan kabuğunuza eklenir, aslında

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

size yazarken böylece stdinpitonun, aslında yazıyoruz ptypsuedo terminali, bir çekirdek cihazı değil, basit bir dosyadır. O kullanır ioctldeğil readve write(ekranınızda çıktı göreceği şekilde, ancak bunun ortaya çıkardığı sürece gönderilmeyecektir python)

Denediğiniz şeyi çoğaltmanın bir yolu a fifoveya 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

Yalnızca screengiriş için de kullanabilirsiniz

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

Boruyu açık tutarsanız (örn. sleep 300 > python_i.pipe &) Diğer taraf kapanmaz ve pythonborudaki komutları kabul etmeye devam eder. Tarafından gönderilen herhangi bir EOF yoktur echo.
roaima

@roaima haklısın, yankının akışı kapattığında EOF'u gönderdiğini anladım. Bu |borularla önlenemez , ancak doğru mu?
crasic

Zaten fifo yolundaydım, ancak echo something > fifobirçok uygulamayı durduracak bir EOF almasına neden olacaktım. sleep infinity > fifoGeçici çözüm olsa benim orta geçmedim, teşekkür ederim!
Sheppy

1
aslında fikrinize devam ederseniz, bunu da yapabilirsiniz python -i <> fifoEOF
Sheppy

11

Erişim , işlem PID'sinin dosya tanımlayıcısı 0'a erişmez , PID'nin dosya tanımlayıcı 0'da açık olduğu dosyaya erişir. Bu ince bir ayrımdır, ancak önemlidir. Dosya tanımlayıcı, bir işlemin bir dosyaya sahip olduğu bir bağlantıdır. Bir dosya tanımlayıcısına yazmak, dosyanın nasıl açıldığına bakılmaksızın dosyaya yazar./proc/PID/fd/0

Eğer normal bir dosya olduğunu yazmadan dosyayı değiştirir. Veriler, işlemin bundan sonra ne okuyacağı anlamına gelmez: işlemin dosyayı okumak için kullandığı dosya tanımlayıcısına bağlı konuma bağlıdır. Bir işlem açıldığında , diğer işlemle aynı dosyayı alır, ancak dosya konumları bağımsızdır./proc/PID/fd/0/proc/PID/fd/0

Eğer bir borudur bu borunun arabelleğe veri ekler, daha sonra yazma. Bu durumda, borudan okunan işlem verileri okuyacaktır./proc/PID/fd/0

Eğer bir terminal olup, o zaman yazılı çıktı olarak bir terminal ile ilgili verileri. Bir terminal dosyası çift yönlüdür: üzerine yazmak veri çıktısı verir, yani terminal metni görüntüler; bir terminalden okuma verileri girer, yani terminal kullanıcı girişini iletir./proc/PID/fd/0

Python terminali hem okuyor hem de yazıyor. Koştuğunuzda terminale echo 'print "Hello"' > /proc/$(pidof python)/fd/0yazıyorsunuz print "Hello". Terminal belirtildiği gibi görüntülenir print "Hello". Python işlemi hiçbir şey görmüyor, hala girdi bekliyor.

Python işlemine girdi beslemek istiyorsanız, terminalin bunu yapmasını sağlamanız gerekir. Bunu yapmanın yolları için crasic'in cevabına bakınız .


2

Gilles'in söylediklerinden yola çıkarak, bir terminale bağlı bir sürecin standartlarına yazmak istiyorsak, aslında bilgiyi terminale göndermemiz gerekir. Ancak, bir terminal bir giriş ve çıkış biçimi olarak hizmet ettiğinden, ona yazarken terminalin "ekran" yerine çalışan bir işleme yazmak istediğinizi bilmesinin bir yolu yoktur.

Bununla birlikte, Linux, kullanıcı TIOCSTItarafından yazılmış gibi bir terminale karakter göndermemizi sağlayan (Terminal G / Ç Kontrolü - Terminal Girişini Simüle Et) adlı bir ioctl isteği aracılığıyla kullanıcı girişini simüle etmenin posix olmayan bir yoluna sahiptir .

Sadece bunun nasıl çalıştığının yüzeysel olarak farkındayım, ancak bu cevaba dayanarak , bunu çizgileri boyunca bir şeyle yapmak mümkün olmalı

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]))

Bazı harici kaynaklar:

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

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


Sorunun belirli bir işletim sistemine özgü olmadığını ve TIOCSTI'nin Linux kaynaklı olmadığını gözlemleyin. Bu yanıtın yazılmasından neredeyse iki yıl önce, insanlar güvenlik nedenleriyle TIOCSTI'yi bırakmaya başladı. unix.stackexchange.com/q/406690/5132
JdeBP

@JdeBP Bu nedenle "Linux" 'u belirtmem (nereden geldiğinden emin olmasam da). Ve "insanlar" derken bazı BSD'leri mi kastediyorsunuz? Bunu yazarken okuduğum kadarıyla, çok daha eski bir uygulamada, o zamandan beri yamalanmış bir güvenlik riski var gibi görünüyor, ancak BSD hala ioctl'i tamamen bırakmayı "daha güvenli" buluyordu. Bununla birlikte, bunların hiçbirine aşina değilim, bu yüzden bu sistemle ilgili hiçbir deneyimim olmadığında belirli sistemlerde bir şeyin mümkün olmadığını söylememeyi daha iyi anladım.
Christian Reall-Fluharty
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.