2012-05-14 15 views
10

मैं अतिरिक्त डायग्नोस्टिक संदेशों को लिखने के लिए एक नया वर्णनकर्ता खोलने के लिए बैश का उपयोग करने की कोशिश कर रहा हूं। मैं stderr का उपयोग नहीं करना चाहता, क्योंकि stderr केवल बैश द्वारा बुलाए गए कार्यक्रमों से आउटपुट होना चाहिए। मैं भी चाहता हूं कि मेरा कस्टम डिस्क्रिप्टर उपयोगकर्ता द्वारा पुनर्निर्देशित किया जा सके।बैश में, मैं एक लिखने योग्य फ़ाइल डिस्क्रिप्टर कैसे खोलूं जो बाहरी रूप से पुनर्निर्देशित है?

exec 3>/dev/tty 
echo foo1 
echo foo2 >&2 
echo foo3 >&3 

लेकिन जब मैं fd 3 रीडायरेक्ट करने के लिए प्रयास करते हैं, उत्पादन अभी भी टर्मिनल के लिए लिखते हैं:

मैं इस कोशिश की।

$ ./test.sh >/dev/null 2>/dev/null 3>/dev/null 
foo3 
+0

एक उपयोगी साइट [कड़ी] (http://www.linuxtopia.org/online_books/advanced_bash_scripting_guide/x13082.html) – Mike

+0

आप एक [नामित पाइप] (http उपयोग करने में सक्षम हो सकता है। die.net/man/1/mkfifo)। स्पष्टीकरण के लिए –

उत्तर

5

काफी सरल: माता-पिता खोल नहीं पुन: निर्देशित हो fd 3 है, तो test.sh/dev/tty को fd 3 पुनः निर्देशित किया जाएगा।// linux:

if ! { exec 0>&3; } 1>/dev/null 2>&1; then 
    exec 3>/dev/tty 
fi 
echo foo1 
echo foo2 >&2 
echo foo3 >&3 
+0

जितना मैं ग्रेग को स्वीकार करना चाहता था, वह अपने जवाब को साफ करने के लिए लगभग 4 सप्ताह में वापस नहीं आया है। यह संभवतः ग्रेगैक से "उधार" की संभावना है, यह सबसे आसान दृष्टिकोण है। – Kelvin

1

अद्यतन

यह किया जा सकता है। सबसे सरल तरीके से कलू का जवाब देखें।

मूल उत्तर

यह जवाब "आप नहीं कर सकते" है लगता है। किसी स्क्रिप्ट में बनाए गए किसी भी वर्णक स्क्रिप्ट पर लागू नहीं होते हैं जिसे स्क्रिप्ट कहा जाता है।

मुझे पता चला कि रूबी का उपयोग करके इसे कैसे किया जाए, हालांकि कोई दिलचस्पी लेता है। Perl का उपयोग कर अद्यतन भी देखें।

begin 
    out = IO.new(3, 'w') 
rescue Errno::EBADF, ArgumentError 
    out = File.open('/dev/tty', 'w') 
end 
p out.fileno 
out.puts "hello world" 

ध्यान दें कि यह स्पष्ट रूप से एक डेमॉन में काम नहीं करेगा - यह टर्मिनल से कनेक्ट नहीं है।

अद्यतन

अगर माणिक अपनी बात नहीं है, तो आप बस माणिक स्क्रिप्ट से एक bash स्क्रिप्ट कॉल कर सकते हैं। आप उत्पादन की विश्वसनीय पाइपिंग के लिए open4 मणि/पुस्तकालय की आवश्यकता होगी:

require 'open4' 

# ... insert begin/rescue/end block from above 

Open4.spawn('./out.sh', :out => out) 

अद्यतन 2

यहाँ पर्ल और ज्यादातर बैश का एक सा का उपयोग कर एक तरीका है। आपको यह सुनिश्चित करना होगा कि पर्ल आपके सिस्टम पर ठीक तरह से काम कर रहा है, क्योंकि एक लापता पर्ल निष्पादन योग्य भी एक गैर-शून्य निकास कोड लौटाएगा।

perl -e 'open(TMPOUT, ">&3") or die' 2>/dev/null 
if [[ $? != 0 ]]; then 
    echo "fd 3 wasn't open" 
    exec 3>/dev/tty 
else 
    echo "fd 3 was open" 
fi 
echo foo1 
echo foo2 >&2 
echo foo3 >&3 
6

सबसे पहले माता-पिता खोल सेट फ़ाइल वर्णनकर्ता के लिए/dev 3/बातिल
फिर अपने कार्यक्रम के लिए/dev/tty
फ़ाइल वर्णनकर्ता 3 सेट तो अपने लक्षणों वास्तव में आश्चर्य की बात नहीं कर रहे हैं।

संपादित करें: आप देखने के लिए अगर fd 3 स्थापित किया गया है की जाँच कर सकते हैं:

if [[ ! -e /proc/$$/fd/3 ]] 
then 
    exec 3>/dev/tty 
fi 
+0

+1। आपके द्वारा निकाला गया समाधान लगभग काम करता है। यह सिर्फ इतना है कि '-t' केवल यह पता लगा सकता है कि एफडी टर्मिनल से जुड़ा हुआ है, भले ही यह अस्तित्व में न हो। – Kelvin

+0

नए सुझाव का प्रयास करें – cdarke

+1

मैंने अभी/proc परीक्षण के बारे में सोचा और फिर आपने इसे पोस्ट किया। महान दिमाग एक जैसे सोचते हैं, शायद। दुर्भाग्य से यह पोर्टेबल नहीं है। लिनक्स में बहुत अच्छा काम करता है, लेकिन मैक नहीं। अगर मैं कर सकता तो मैं एक और अपवित्रता दूंगा। – Kelvin

2

यहाँ अगर एक फ़ाइल वर्णनकर्ता पहले से ही (बैश) केवल खोल का उपयोग कर स्थापित किया गया है की जाँच करने के लिए एक तरीका है।

(
# cf. "How to check if file descriptor exists?", 
# http://www.linuxmisc.com/12-unix-shell/b451b17da3906edb.htm 

exec 3<<<hello 

# open file descriptors get inherited by child processes, 
# so we can use a subshell to test for existence of fd 3 
(exec 0>&3) 1>/dev/null 2>&1 && 
    { echo bash: fd exists; fdexists=true; } || 
    { echo bash: fd does NOT exists; fdexists=false; } 

perl -e 'open(TMPOUT, ">&3") or die' 1>/dev/null 2>&1 && 
    echo perl: fd exists || echo perl: fd does NOT exist 

${fdexists} && cat <&3 
) 
+0

+1 यह सही लगता है। मैं कुछ और परीक्षण करूंगा। लेकिन आपको पर्ल भाग को अलग करना चाहिए, क्योंकि ऐसा लगता है कि यह स्क्रिप्ट का हिस्सा है। अधिक बारीकी से पढ़ने के बाद, मुझे लगता है कि आप केवल तुलना के लिए इसका उपयोग कर रहे हैं। साथ ही, मुझे यकीन नहीं है कि 'exec 3 <<< हैलो' का उद्देश्य क्या है; इसे 'fdexists' परीक्षण से पहले डालने से परीक्षा हर बार सच हो जाएगी। – Kelvin

+0

मैंने पुष्टि की है कि इसका सही विचार है, लेकिन इसे सफाई की आवश्यकता है। यदि आप मेरे प्रश्न में स्क्रिप्ट ले सकते हैं और इसे अपने समाधान के साथ संशोधित कर सकते हैं, तो मैं आपका जवाब स्वीकार करूंगा। – Kelvin

+0

'perl' हिस्सा एक वैकल्पिक समाधान है। 'exec 3 <<< हैलो 'परीक्षण के लिए है। फ़ाइल लाइन डिस्क्रिप्टर को बाहर से रीडायरेक्ट करने के समान ही इस लाइन को असम्बद्ध करना एक ही प्रभाव है। –

1

@ केल्विन: यहां आपकी संशोधित स्क्रिप्ट है जिसे आपने पूछा (साथ ही कुछ परीक्षण)।

echo ' 
#!/bin/bash 

# If test.sh is redirecting fd 3 to somewhere, fd 3 gets redirected to /dev/null; 
# otherwise fd 3 gets redirected to /dev/tty. 
#{ exec 0>&3; } 1>/dev/null 2>&1 && exec 3>&- || exec 3>/dev/tty 
{ exec 0>&3; } 1>/dev/null 2>&1 && exec 3>/dev/null || exec 3>/dev/tty 

echo foo1 
echo foo2 >&2 
echo foo3 >&3 

' > test.sh 

chmod +x test.sh 

./test.sh 
./test.sh 1>/dev/null 
./test.sh 2>/dev/null 
./test.sh 3>/dev/null 
./test.sh 1>/dev/null 2>/dev/null 
./test.sh 1>/dev/null 2>/dev/null 3>&- 
./test.sh 1>/dev/null 2>/dev/null 3>/dev/null 
./test.sh 1>/dev/null 2>/dev/null 3>/dev/tty 

# fd 3 is opened for reading the Here String 'hello' 
# test.sh should see that fd 3 has already been set by the environment 
# man bash | less -Ip 'here string' 
exec 3<<<hello 
cat <&3 
# If fd 3 is not explicitly closed, test.sh will determine fd 3 to be set. 
#exec 3>&- 
./test.sh 

exec 3<<<hello 
./test.sh 3>&- 
+0

यह आपके मूल उत्तर में इसे संपादित करके सबसे अच्छा रखा जाएगा। –

+0

इसके अलावा, आपको एक नए के बजाय अपने मूल SO खाते का उपयोग करना चाहिए। – Kelvin

+0

क्षमा करें, यह काम नहीं करता है। अगर मैं स्क्रिप्ट चलाता हूं, एफडी 3 को फाइल में रीडायरेक्ट करता हूं, तो इसमें कुछ भी लिखा नहीं जाता है। – Kelvin