क्या मैं स्क्रीन सत्र में सक्रिय प्रक्रिया के STDIN को कुछ पाठ भेज सकता हूं?


70

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

क्या कोई स्मार्ट पुनर्निर्देशन गर्भनिरोधक है जो मैं एक क्रोनजोब भेजने के लिए कर सकता हूं जो हर दिन एक निश्चित समय पर कमांड को रोक देता है?

जवाबों:


85

यह उत्तर समस्या को हल नहीं करता है, लेकिन यह यहां छोड़ दिया गया है क्योंकि 30+ लोगों ने इसे उपयोगी पाया , अन्यथा मैंने इसे बहुत पहले ही हटा दिया था।

को लिखें /proc/*pid of the program*/fd/0fdउपनिर्देशिका सभी खोली गई फ़ाइलों की वर्णनकर्ता होता है और फ़ाइल वर्णनकर्ता 0मानक इनपुट (1 stdout है और 2 stderr है)।

आप इसका उपयोग टैटी पर संदेशों को आउटपुट करने के लिए कर सकते हैं जहां कोई प्रोग्राम चल रहा है, हालांकि यह आपको प्रोग्राम को लिखने की अनुमति नहीं देता है।

उदाहरण

टर्मिनल 1:

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

टर्मिनल 2:

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

3
@ जेम्स लॉरी: फिर proc (5) और proc.txt पर एक नज़र है ।
क्रिस्टियन सियुपिटु

2
+2 कोई फर्क नहीं पड़ता कि आप कितना सोचते हैं कि आप जानते हैं, सीखने के लिए हमेशा अधिक है :) चालाक।
ट्रायेंगेल सेप

3
हालांकि यह जान लें कि खरीद केवल उसी चीज को पुनर्निर्देशित करती है जिसका उपयोग स्टड के स्रोत के रूप में किया जाता है। आपके उदाहरण में, यदि आप टर्मिनल 1 में कुछ दर्ज करते हैं, तो इसे फिर से प्रिंट किया जाएगा (यह बिल्लियों को स्टडिन और बिल्ली को प्रिंट करता है), इस प्रकार आपको दो बार देखने के परिणामस्वरूप। दूसरी ओर यदि आप fd / 0 पर कुछ भेजते हैं तो इसे कंसोल पर भेजा जाएगा, लेकिन बिल्ली को नहीं, और इस प्रकार केवल एक बार प्रदर्शित किया जाएगा। चूंकि बिल्ली बस इस उदाहरण के साथ फिर से इनपुट प्रिंट करती है, तो आप वास्तव में यह नहीं देख सकते हैं कि आपका इनपुट या आउटपुट प्रिंट हो रहा है या नहीं, इस प्रकार यह गलत धारणा है। कंसोल / पीटी के लिए / एफडी / 0 अंक; देखते हैं ls -l /proc/7417/fd/0
Kissaki

4
वास्तविक दुनिया उदाहरण: मैंने gphoto2 --get-all-files की शुरुआत की है और यह 100 बार पुष्टिकरण मांगता है। जब मैं "y"> / proc / PID / fd / 0 प्रतिध्वनि करता हूं, तो gphoto2 आगे नहीं बढ़ता है, हालांकि, टर्मिनल में "y" मुद्रित होता है।
थोरस्टेन स्टैक

2
@ThorstenStaerk, मुझे पता है, इसीलिए मैंने वह नोट जोड़ा है। आप केवल टर्मिनल के संगत डिवाइस फ़ाइल पर लिख रहे हैं, जिस पर gphoto2 चलता है (जैसे /dev/pts/19), yवर्ण स्वयं एप्लिकेशन तक नहीं पहुंचता है। जब आप राइट (1) कमांड का उपयोग करते हैं तो ऐसा ही होता है । वैसे भी, या तो मेरे दूसरे जवाब की कोशिश करो या xdotool की तरह एक ग्राफिकल ऑटोमेशन टूल ।
क्रिस्टियान सियुपिटु

36

स्क्रीन आधारित समाधान

सर्वर को इस तरह शुरू करें:

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

स्क्रीन अलग मोड में शुरू होगी, इसलिए यदि आप देखना चाहते हैं कि क्या चल रहा है, तो चलाएं:

# screen -r ServerFault

सर्वर को इस तरह नियंत्रित करें:

# 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

(यह उत्तर यूनिक्स और लिनक्स सिबलिंग साइट से अलग स्क्रीन पर टेक्स्ट इनपुट भेजने पर आधारित है )

मापदंडों की व्याख्या :

-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.

सामान [स्ट्रिंग]

   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 आधारित समाधान

सर्वर को इस तरह शुरू करें:

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

tmux अलग मोड में शुरू होगा, इसलिए यदि आप देखना चाहते हैं कि क्या चल रहा है, तो चलाएं:

# tmux attach-session -t ServerFault

सर्वर को इस तरह नियंत्रित करें:

# 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

मापदंडों की व्याख्या :

 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

इसे शुरू करने की कोशिश करें:

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

और यह मारने के लिए:

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

3
यह अच्छा है, लेकिन इसका नुकसान यह हो सकता है कि प्रोग्राम चलने के दौरान अन्य कमांड भेजने में सक्षम न हो। यदि स्टड पर ईओएफ हिट होने पर प्रोग्राम बंद हो जाता है, तो पहले echo "xxx" > cmdप्रोग्राम बंद हो जाएगा (क्योंकि पाइप बंद हो जाएगा)। हालांकि कुछ प्रोग्राम काफी स्मार्ट होते हैं, rewind(3)जब ईओएफ से उनका सामना होता है।
क्रिस्टियन सियुपिटु

2

screenउपयोगिता, या किसी अन्य फैंसी उपयोगिता को चलाने के बिना चल रहे प्रक्रिया को इनपुट पाठ भेजना संभव है । और यह इनपुट टेक्स्ट को प्रक्रिया 'मानक इनपुट "फ़ाइल" पर भेजकर किया जा सकता है /proc/PID#/fd/0

हालाँकि, इनपुट पाठ को प्रक्रिया द्वारा पढ़ने के लिए एक विशेष तरीके से भेजने की आवश्यकता होती है। नियमित फ़ाइल writeविधि के माध्यम से इनपुट टेक्स्ट भेजने से प्रक्रिया को टेक्स्ट प्राप्त नहीं होगा। ऐसा इसलिए है क्योंकि ऐसा करने से वह केवल उस "फ़ाइल" पर ही लागू होगा, लेकिन बाइट्स को पढ़ने के लिए प्रक्रिया को ट्रिगर नहीं करेगा।

बाइट्स पढ़ने के लिए प्रक्रिया को ट्रिगर करने के लिए, हर एक बाइट को भेजने के लिए IOCTLप्रकार का एक ऑपरेशन करना आवश्यक है TIOCSTI। यह बाइट को प्रक्रिया की मानक इनपुट कतार में रखेगा।

सी, पर्ल, और पायथन में कुछ उदाहरणों के साथ यहां चर्चा की गई है:

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

-

तो लगभग 9 साल पहले पूछे गए मूल प्रश्न का उत्तर देने के लिए, क्रोन नौकरी को कुछ छोटे उपयोगिता स्क्रिप्ट / कार्यक्रम चलाने की आवश्यकता होगी, उदाहरण के लिए लोगों ने उस अन्य प्रश्न के लिए लिखा था, जो उस सर्वर प्रक्रिया को स्ट्रिंग "स्टॉप \ एन" भेजेगा। प्रश्न में, IOCTLटाइप के एक ऑपरेशन के माध्यम से 5 बाइट्स में से प्रत्येक को भेजकर TIOCSTI

बेशक, यह केवल उन सिस्टम पर काम करेगा जो TIOCSTI IOCTLऑपरेशन प्रकार (जैसे लिनक्स) का समर्थन करते हैं , और केवल rootउपयोगकर्ता खाते से, क्योंकि ये "फाइलें" इसके अंतर्गत /proc/"स्वामित्व" हैं root


1

मामले में यह किसी को भी मदद करता है:
मुझे एक समान समस्या थी, और जिस प्रक्रिया का मैं उपयोग कर रहा था, वह नहीं था screenया tmux, मुझे एक अलग दृष्टिकोण लेना था।

मैं संलग्न gdbकरने के लिए xtermहै कि मेरे प्रक्रिया में चल रहा था, और उपयोग call write(5, "stop\n", 5)से gdbमास्टर Pty फ़ाइल वर्णनकर्ता को लिखने के लिए।
मुझे पता चला कि किस फाइल डिस्क्रिप्टर ने /proc/<pid>/fdलिंक के लिए /dev/ptmxऔर फिर दोनों विकल्पों के बीच के परीक्षण और त्रुटि को देखने के लिए डेटा भेजने के लिए भेजा (मेरे स्ट्रिंग को दोनों मेलिंग फाइल डिस्क्रिप्टर पर भेजने से कोई नुकसान नहीं हुआ)।

संपादित करें

यह पता चला कि xtermमैंने जो प्रक्रिया संलग्न की थी वह spawn-new-terminal() xtermएक कीबाइंडिंग से क्रिया के साथ उत्पन्न हुई थी , और दूसरी ptmxफ़ाइल डिस्क्रिप्टर खुली बस ptmxउस मूल xtermप्रक्रिया की थी जिसे बंद नहीं किया गया था।
इसलिए परीक्षण और त्रुटि कॉल ने उस अन्य टर्मिनल को आउटपुट भेजा था।
अधिकांश xtermप्रक्रियाओं में दो ptmxफ़ाइल विवरण नहीं होते हैं ।

END EDIT

इसने प्रभावी रूप से उस स्ट्रिंग को टर्मिनल में टाइप किया, और इसलिए इसे इसके अंतर्गत चल रही प्रक्रिया के साथ भेज दिया।

nb आपको कुछ के साथ एक चल रही प्रक्रिया में संलग्न करने की अनुमति देने की आवश्यकता हो सकती है
sudo bash -c "echo 0 > /proc/sys/kernel/yama/ptrace_scope"


0

चूँकि मैं क्रिस्टियन सियुपिटु (2010 में) के सबसे स्वीकृत उत्तर पर टिप्पणी नहीं कर सकता, इसलिए मुझे इसे अलग उत्तर में रखना होगा:

यह प्रश्न इस थ्रेड में पहले से ही हल किया गया था: https://stackoverflow.com/questions/5374255/how-to-write-data-to-existing-processs-stdin-from-external-process

संक्षेप में:

आपको स्टड के लिए एक पाइप के साथ अपनी प्रक्रिया शुरू करनी होगी जो वर्तमान इनपुट के माध्यम से लिखे जाने पर ब्लॉक नहीं करता है और न ही बंद होता है। यह एक सरल अंतहीन लूप द्वारा कार्यान्वित किया जा सकता है जिसे प्रश्न में प्रक्रिया के लिए पाइप किया जाएगा:

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

मैं यह पुष्टि कर सकता हूं कि यह एक पाइप खोलने के क्रिसी के तरीके से अलग है जो मेरे मामले में काम नहीं कर रहा था। दिखाए गए समाधान के बजाय काम किया।

फिर आप उसे निर्देश भेजने के लिए ... / fd / 0 प्रक्रिया की फ़ाइल लिख सकते हैं। एकमात्र दोष यह है कि आपको बैश प्रक्रिया को समाप्त करने की आवश्यकता है जो सर्वर बंद होने के बाद अंतहीन लूप को निष्पादित कर रहा है।

हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.