संवाद के अपने औजारों का उपयोग करना:
यदि आप डायलॉग के लिए मैन पेज पढ़ते हैं, तो विकल्प है --output-fd
, जो आपको स्पष्ट रूप से सेट करने की अनुमति देता है कि आउटपुट कहां जाता है (STDOUT 1, STDERR 2), बजाय डिफ़ॉल्ट रूप से STDERR के।
Bellow आप मुझे नमूना dialog
आदेश चलाते हुए देख सकते हैं , स्पष्ट रूप से यह बताते हुए कि आउटपुट को फाइल डिस्क्रिप्टर 1 में जाना चाहिए, जो मुझे इसे MYVAR में सहेजने की अनुमति देता है।
MYVAR=$(dialog --inputbox "THIS OUTPUT GOES TO FD 1" 25 25 --output-fd 1)
नामित पाइप का उपयोग करना
वैकल्पिक दृष्टिकोण जिसमें बहुत अधिक छिपी हुई क्षमता है, जिसे नामित पाइप के रूप में जाना जाता है ।
#!/bin/bash
mkfifo /tmp/namedPipe1 # this creates named pipe, aka fifo
# to make sure the shell doesn't hang, we run redirection
# in background, because fifo waits for output to come out
dialog --inputbox "This is an input box with named pipe" 40 40 2> /tmp/namedPipe1 &
# release contents of pipe
OUTPUT="$( cat /tmp/namedPipe1 )"
echo "This is the output " $OUTPUT
# clean up
rm /tmp/namedPipe1
वैकल्पिक दृष्टिकोण के साथ user.dz के उत्तर का अधिक गहराई से अवलोकन
User.dz और ByteCommander की उस द्वारा दिए गए स्पष्टीकरण का मूल उत्तर दोनों एक अच्छा समाधान और यह क्या करता है का अवलोकन प्रदान करते हैं। हालाँकि, मेरा मानना है कि एक गहन विश्लेषण यह समझाने में लाभदायक हो सकता है कि यह क्यों काम करता है।
सबसे पहले, दो चीजों को समझना महत्वपूर्ण है: हम किस समस्या को हल करने की कोशिश कर रहे हैं और शेल तंत्र के अंतर्निहित कामकाज क्या हैं जिसके साथ हम काम कर रहे हैं। कार्य कमांड प्रतिस्थापन के माध्यम से एक कमांड के आउटपुट को कैप्चर करना है। सभी को पता है कि सरलीकृत अवलोकन के तहत, कमांड प्रतिस्थापन stdout
एक कमांड पर कब्जा कर लेते हैं और इसे कुछ और द्वारा पुन: उपयोग किया जाता है। इस मामले में, result=$(...)
भाग ...
को एक चर नाम से जो भी कमांड निर्दिष्ट किया गया है उसके आउटपुट को सहेजना चाहिए result
।
हुड के नीचे, कमांड प्रतिस्थापन वास्तव में पाइप के रूप में कार्यान्वित किया जाता है, जहां एक बच्चे की प्रक्रिया होती है (वास्तविक कमांड जो चलती है) और पढ़ने की प्रक्रिया (जो चर को आउटपुट बचाता है)। यह सिस्टम कॉल के एक सरल ट्रेस के साथ स्पष्ट है। ध्यान दें कि फ़ाइल डिस्क्रिप्टर 3 पाइप का रीड एंड है, जबकि 4 राइट एंड है। की बाल प्रक्रिया के लिए echo
, जो इसे लिखता है stdout
- फाइल डिस्क्रिप्टर 1, वह फाइल डिस्क्रिप्टर वास्तव में फाइल डिस्क्रिप्टर 4 की कॉपी है, जो पाइप का राइट-एंड है। ध्यान दें कि stderr
यहां एक भूमिका नहीं है, केवल इसलिए कि यह stdout
केवल एक पाइप कनेक्ट है ।
$ strace -f -e pipe,dup2,write,read bash -c 'v=$(echo "X")'
...
pipe([3, 4]) = 0
strace: Process 6200 attached
[pid 6199] read(3, <unfinished ...>
[pid 6200] dup2(4, 1) = 1
[pid 6200] write(1, "X\n", 2 <unfinished ...>
[pid 6199] <... read resumed> "X\n", 128) = 2
[pid 6200] <... write resumed> ) = 2
[pid 6199] read(3, "", 128) = 0
[pid 6200] +++ exited with 0 +++
--- SIGCHLD {si_signo=SIGCHLD, si_code=CLD_EXITED, si_pid=6200, si_uid=1000, si_status=0, si_utime=0, si_stime=0} ---
+++ exited with 0 +++
चलो एक दूसरे के लिए मूल उत्तर पर वापस जाएं। चूंकि अब हम जानते dialog
हैं कि TUI बॉक्स को लिखता है stdout
, उत्तर देता है stderr
, और कमांड प्रतिस्थापन के भीतर stdout
कहीं और पाइप किया जाता है, हमारे पास पहले से ही समाधान का हिस्सा है - हमें फ़ाइल डिस्क्रिप्टर को इस तरह से stderr
फिर से तैयार करने की आवश्यकता है जो रीडर प्रक्रिया के लिए पाइप किया जाएगा। यह 2>&1
उत्तर का हिस्सा है। हालांकि, हम टीयूआई बॉक्स के साथ क्या करते हैं?
dup2()
यहीं पर फाइल डिस्क्रिप्टर 3 आता है। syscall हमें फाइल डिस्क्रिप्टर को डुप्लिकेट करने की अनुमति देता है, जिससे वे प्रभावी रूप से एक ही स्थान पर संदर्भित होते हैं, फिर भी हम उन्हें अलग से जोड़ सकते हैं। उन प्रक्रियाओं के फ़ाइल डिस्क्रिप्टर जो टर्मिनल से जुड़े होते हैं, वास्तव में विशिष्ट टर्मिनल डिवाइस की ओर इशारा करते हैं। यह स्पष्ट है अगर तुम करते हो
$ ls -l /proc/self/fd
total 0
lrwx------ 1 user1 user1 64 Aug 20 10:30 0 -> /dev/pts/5
lrwx------ 1 user1 user1 64 Aug 20 10:30 1 -> /dev/pts/5
lrwx------ 1 user1 user1 64 Aug 20 10:30 2 -> /dev/pts/5
lr-x------ 1 user1 user1 64 Aug 20 10:30 3 -> /proc/6424/fd
/dev/pts/5
मेरा वर्तमान छद्म टर्मिनल उपकरण कहां है। इस प्रकार, अगर हम किसी तरह इस गंतव्य को बचा सकते हैं, तो हम अभी भी टर्मिनल स्क्रीन पर टीयूआई बॉक्स लिख सकते हैं। वही exec 3>&1
करता है। जब आप command > /dev/null
उदाहरण के लिए पुनर्निर्देशन के साथ एक कमांड को कॉल करते हैं , तो शेल यह stdout फाइल डिस्क्रिप्टर पास करता है और फिर dup2()
उस फाइल डिस्क्रिप्टर को लिखने के लिए उपयोग करता है /dev/null
। exec
आदेश प्रदर्शन कुछ के लिए इसी तरहdup2()
पूरे खोल सत्र के लिए फ़ाइल वर्णनकर्ता, इस प्रकार किसी भी कमांड इनहेरिट पहले से ही निर्देशित कर दिये फ़ाइल वर्णनकर्ता बना रही है। उसी के साथ exec 3>&1
। फाइल डिस्क्रिप्टर 3
अब कंट्रोलिंग टर्मिनल को इंगित / इंगित करेगा, और उस शेल सत्र में चलने वाले किसी भी कमांड को इसके बारे में पता चल जाएगा।
जब ऐसा result=$(dialog --inputbox test 0 0 2>&1 1>&3);
होता है, तो शेल डायलॉग लिखने के लिए एक पाइप बनाता है, लेकिन 2>&1
सबसे पहले कमांड की फाइल डिस्क्रिप्टर 2 को उस पाइप के राइट फाइल डिस्क्रिप्टर पर डुप्लिकेट किया जाएगा (इस प्रकार आउटपुट को पाइप के अंत और वेरिएबल में पढ़ने के लिए जाना जाता है) , जबकि फ़ाइल डिस्क्रिप्टर 1 को 3 पर डुप्लिकेट किया जाएगा। यह फ़ाइल डिस्क्रिप्टर 1 को अभी भी कंट्रोलिंग टर्मिनल को संदर्भित करेगा, और टीयूआई संवाद स्क्रीन पर दिखाई देगा।
अब, प्रक्रिया के वर्तमान नियंत्रण टर्मिनल के लिए वास्तव में एक शॉर्ट-हैंड है, जो है /dev/tty
। इस प्रकार, फ़ाइल विवरणकों के उपयोग के बिना समाधान को सरल बनाया जा सकता है, बस इसमें:
result=$(dialog --inputbox test 0 0 2>&1 1>/dev/tty);
echo "$result"
याद रखने योग्य मुख्य बातें:
- फ़ाइल डिस्क्रिप्टर प्रत्येक कमांड द्वारा शेल से विरासत में मिले हैं
- कमांड प्रतिस्थापन को पाइप के रूप में लागू किया जाता है
- डुप्लिकेट फ़ाइल डिस्क्रिप्टर एक ही मूल के रूप में एक ही स्थान को संदर्भित करेगा, लेकिन हम प्रत्येक फ़ाइल डिस्क्रिप्टर को अलग से जोड़ सकते हैं
यह सभी देखें
mktemp
एक अस्थायी फ़ाइल बनाने के लिए कमांड का उपयोग कर सकते हैं ।