Bir ekran oturumunda çalışan aktif bir işlemin STDIN'ine biraz metin gönderebilir miyim?


70

Linux sunucumdaki bir ekran oturumunda uzun süredir devam eden bir sunucu işlemim var. Biraz dengesiz (ve ne yazık ki yazılımım değil, bu yüzden bunu düzeltemiyorum!), Bu yüzden kararlılığı sağlamak için işlemin her gece yeniden başlatılmasını istiyorum. Zarif bir kapatma işlemi yapmanın tek yolu ekran işlemine gitmek, içinde bulunduğu pencereye geçmek ve kontrol konsolunda "stop" dizisini girmek.

Her gün sabit bir zamanda bu dur komutunu göndermek için bir cronjob yapmak için yapabileceğim herhangi bir akıllı yönlendirme sıkışıklığı var mı?

Yanıtlar:


85

Bu cevap sorunu çözmüyor, ancak burada kaldı çünkü 30+ insan yararlı buldu , yoksa uzun zaman önce silerdim.

Yaz /proc/*pid of the program*/fd/0. Alt fddizin, açılan tüm dosyaların tanımlayıcılarını içerir ve dosya tanımlayıcısı 0standart girdidir (1, stdout ve 2, stderr'dir).

Bunu, bir programın çalıştığı tty'ye, programın kendisine yazmanıza izin vermese de, iletileri almak için kullanabilirsiniz.

Örnek

Terminal 1:

[ciupicri@hermes ~]$ cat
shows on the tty but bypasses cat

Terminal 2:

[ciupicri@hermes ~]$ pidof cat
7417
[ciupicri@hermes ~]$ echo "shows on the tty but bypasses cat" > /proc/7417/fd/0


2
Ne kadar bildiğini sanırsan düşün, +2, öğrenecek daha çok şey var :) kaygan.
troyengel

3
Proc fd'nin yalnızca bir stdin kaynağı olarak kullanılana yönlendirdiğini unutmayın. Örnekte, terminal 1'e bir şey girerseniz, tekrar yazdırır (stdin'e gönderilir ve kedi yazdırır), böylece iki kez görmenize neden olur. Öte yandan, eğer fd / 0 'a birşeyler gönderirseniz, konsola gönderilir ancak kedi gönderilmez ve bu nedenle sadece bir kez gösterilir. Cat, bu örnekle girişi tekrar yazdırırken, giriş veya çıktınızın yazdırılıp yazdırılmadığını gerçekten göremezsiniz, bu nedenle bu yanlış anlama. / fd / 0 konsola / puanlara işaret eder; bkz ls -l /proc/7417/fd/0.
Kissaki

4
gerçek dünya örneği: gphoto2 - all-all-files'ı başlattım ve 100 kez onay istedi. "Y"> / proc / PID / fd / 0 ekosunu yaptığımda, gphoto2 ilerlemiyor, ancak terminalde "y" yazdırılıyor.
Thorsten Staerk

2
@ThorstenStaerk, biliyorum, bu yüzden bu notu ekledim. Yalnızca gphoto2'nin çalıştığı terminale karşılık gelen aygıt dosyasına yazıyorsunuz (örn. /dev/pts/19), yKarakter uygulamanın kendisine ulaşmıyor. Write (1) komutunu kullanırken olanlara benzer . Her neyse, ya diğer cevabımı ya da xdotool gibi bir grafik otomasyon aracını deneyin .
Cristian Ciupitu

36

Ekran tabanlı çözüm

Sunucuyu şu şekilde başlatın:

# screen -d -m -S ServerFault tr a-z A-Z # replace with your server

Ekran ayrılmış modda başlayacaktır, bu yüzden neler olup bittiğini görmek istiyorsanız, koşun:

# screen -r ServerFault

Sunucuyu şu şekilde kontrol et:

# screen -S ServerFault -p 0 -X stuff "stop^M"
# screen -S ServerFault -p 0 -X stuff "start^M"
# screen -S ServerFault -p 0 -X stuff "^D" # send EOF

(Bu cevap dayanmaktadır müstakil bir ekrana metin girişi göndererek gelen Unix & Linux kardeş sitesi)

Parametrelerin açıklaması :

-d -m
   Start screen in "detached" mode. This creates a new session but doesn't
   attach to it.  This is useful for system startup scripts.
-S sessionname
   When creating a new session, this option can be used to specify a meaningful
   name for the session.
-r [pid.tty.host]
-r sessionowner/[pid.tty.host]
   resumes a detached screen session.
-p number_or_name|-|=|+
   Preselect a window. This is useful when you want to reattach to a specific
   window or you want to send a command via the "-X" option to a specific
   window.
-X
   Send the specified command to a running screen session e.g. stuff.

malzeme [string]

   Stuff the string string in the input  buffer of the current window.
   This is like the "paste" command but with much less overhead.  Without
   a parameter, screen will prompt for a string to stuff.

tmux tabanlı çözüm

Sunucuyu şu şekilde başlatın:

# tmux new-session -d -s ServerFault 'tr a-z A-Z' # replace with your server

tmux ayrılmış modda başlayacaktır, yani ne olup bittiğini görmek istiyorsanız, koşun:

# tmux attach-session -t ServerFault

Sunucuyu şu şekilde kontrol et:

# tmux send-keys -t ServerFault -l stop
# tmux send-keys -t ServerFault Enter
# tmux send-keys -t ServerFault -l start
# tmux send-keys -t ServerFault Enter
# tmux send-keys -t ServerFault C-d # send EOF

Parametrelerin açıklaması :

 new-session [-AdDP] [-c start-directory] [-F format] [-n window-name] [-s
         session-name] [-t target-session] [-x width] [-y height]
         [shell-command]
         Create a new session with name session-name.

         The new session is attached to the current terminal unless -d is
         given.  window-name and shell-command are the name of and shell
         command to execute in the initial window.  If -d is used, -x and
         -y specify the size of the initial window (80 by 24 if not
         given).

 send-keys [-lR] [-t target-pane] key ...
               (alias: send)
         Send a key or keys to a window.  Each argument key is the name of
         the key (such as `C-a' or `npage' ) to send; if the string is not
         recognised as a key, it is sent as a series of characters.  The
         -l flag disables key name lookup and sends the keys literally.

4

Başlamak için bunu dene:

# screen
# cd /path/to/wd
# mkfifo cmd
# my_cmd <cmd
C-A d

Ve bunu öldürmek için:

# cd /path/to/wd
# echo "stop" > cmd
# rm cmd

3
Bu iyidir, ancak program çalışırken başka bir komut gönderememek dezavantajına sahip olabilir. Program stdin'e EOF'ye bastığında durursa, ilk echo "xxx" > cmdönce program durur (çünkü boru kapanacaktır). Bazı programlar rewind(3)EOF ile karşılaştıklarında stdinlerini ( ) yeniden açacak kadar akıllı olsalar da.
Cristian Ciupitu

2

Giriş metnini screenyardımcı programı veya başka herhangi bir süslü yardımcı programı çalıştırmadan çalışan bir işleme göndermek mümkündür . Ve bu giriş metnini 'standart giriş "dosya" işlemine göndererek de yapılabilir /proc/PID#/fd/0.

Ancak, giriş metninin işlem tarafından okunması için özel bir şekilde gönderilmesi gerekir. Giriş metnini normal dosya writeyöntemiyle göndermek, işlemin metni almasına neden olmaz. Bunun nedeni sadece "dosyaya" eklenecek, ancak baytları okuma işlemini tetiklemeyecek olmasıdır.

Baytları okumak için işlemi tetiklemek için, gönderilecek her bayt için bir IOCTLtür işlem TIOCSTIyapılması gerekir. Bu, baytı işlemin standart giriş sırasına yerleştirir.

Burada, C, Perl ve Python'daki bazı örneklerle tartışılmaktadır:

https://unix.stackexchange.com/questions/48103/construct-a-command-by-putting-a-string-into-a-tty/48221

-

Bu nedenle, neredeyse 9 yıl önce sorulan orijinal soruyu cevaplamak için, cron işinin, o sunucu işlemine "stop \ n" dizesini gönderecek olan, başka bir soru için insanların yazdığı örneklere benzer bir küçük yardımcı program betiği / programı çalıştırması gerekecektir. Soruda, 5 bayttan her birini bir tür IOCTLişlemle göndererek TIOCSTI.

Tabii ki bu sadece TIOCSTI IOCTLişletim türünü destekleyen sistemler üzerinde çalışacaktır (Linux gibi) ve yalnızca rootkullanıcı hesabından, bu "dosyalar" altındaki /proc/"sahip oldukları" dir root.


1

Kimseye yardım etmesi durumunda:
Benzer bir sorun yaşadım ve kullandığım işlem altında değildi screenya da tmuxfarklı bir yaklaşım izlemem gerekti.

Ben ekli gdbiçin xtermbenim süreç çalışan olduğunu ve kullanılan call write(5, "stop\n", 5)gelen gdbana Pty dosya tanımlayıcı yazmak için.
Hangi dosya tanımlayıcısının, /proc/<pid>/fdbir bağlantı arayarak veriyi göndereceğini /dev/ptmxve ardından iki seçenek arasındaki deneme ve yanılmayı buldum (dizgemi her iki eşleşen dosya tanımlayıcısına da göndermem zarar vermeyecek gibi görünüyordu).

DÜZENLE

O çıktı xtermben kökenli edildi bağlı olan işlem spawn-new-terminal() xtermbir keybinding gelen eylem ve ikinci ptmxdosya tanıtıcı açık basitçe ptmxebeveyn arasında xtermkapalı olmasaydı süreç.
Bu nedenle, deneme ve hata çağrıları diğer terminale çıktı gönderdi.
Çoğu xtermişlem iki ptmxdosya tanımlayıcısına sahip değildir .

SON DÜZENLEME

Bu, bu dizgiyi terminale etkili bir şekilde yazdı ve bu nedenle onu altında çalışan işleme yolladı.

nb gibi bir şeyle çalışan bir işleme bağlanmanıza izin vermeniz gerekebilir
sudo bash -c "echo 0 > /proc/sys/kernel/yama/ptrace_scope"


0

Cristian Ciupitu'nun (2010) en çok kabul edilen cevabını yorumlayamadığım için, bunu ayrı bir cevaba vermeliyim:

Bu soru zaten bu konuya çözüldü: https://stackoverflow.com/questions/5374255/how-to-write-data-to-existing-processs-stdin-from-external-process

Kısacası:

İşleminizi, stdin girişi için geçerli giriş yazılırken bloke etmeyen veya kapanmayan bir boru ile başlatmanız gerekir. Bu, söz konusu işleme yönlendirilecek olan basit bir sonsuz döngü ile gerçekleştirilebilir:

$ (while [ 1 ]; do sleep 1; done) | yourProgramToStart

Bunun, Krissi'nin benim durumumda çalışmayan bir boru açma şeklinin farklı olduğunu onaylayabilirim. Gösterilen çözüm işe yaradı.

Daha sonra talimat göndermek için işlemin ... / fd / 0 dosyasına yazabilirsiniz. Tek dezavantajı, sunucu kapatıldıktan sonra sonsuz döngüyü yürüten bash işlemini de sonlandırmanız gerektiğidir.

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.