यदि फ़ाइल डिस्क्रिप्टर मान्य है तो परीक्षण


12

जब वे खुले हों, तो मैं विवरणकर्ताओं (एफडी) को 3 से अधिक या उसके बराबर फ़ाइल करने के लिए बैश स्क्रिप्ट आउटपुट अतिरिक्त जानकारी देना चाहता हूं। एफडी खुली है या नहीं, यह जांचने के लिए, मैंने निम्नलिखित ट्रिक तैयार की:

if (printf '' 1>&3) 2>&-; then
  # File descriptor 3 is open
else
  # File descriptor 3 is not open
fi

यह मेरी जरूरतों के लिए पर्याप्त है, लेकिन मैं इस बात के लिए उत्सुक हूं कि क्या एफडी वैध है या नहीं, परीक्षण का एक और अधिक मुहावरेदार तरीका है। मुझे इस बारे में विशेष रूप से दिलचस्पी है कि क्या fcntl(1)शेल कमांड में मैपिंग कमांड मौजूद है, जो एफडी झंडे की पुनर्प्राप्ति की अनुमति देगा ( O_WRONLYऔर O_RDWRयह जांचने के लिए कि एफडी लिखने योग्य है, O_RDONLYऔर O_RDWRयह जांचने के लिए कि एफडी पठनीय है)।

जवाबों:


12

में ksh(दोनों एटी एंड टी और pdksh वेरिएंट) या zsh, आप कर सकते हैं:

if print -nu3; then
  echo fd 3 is writeable
fi

वे उस fd पर कुछ भी नहीं लिखेंगे, लेकिन फिर भी जाँच लें कि क्या fd लिखने योग्य है (उपयोग करते हुए fcntl(3, F_GETFL)) और अन्यथा किसी त्रुटि की रिपोर्ट करें:

$ ksh -c 'print -nu3' 3< /dev/null
ksh: print: -u: 3: fd not open for writing

(जिसे आप रीडायरेक्ट कर सकते हैं /dev/null)।

साथ bash, मुझे लगता है कि अपने ही एकमात्र विकल्प है, तो एक जांच करने के लिए है dup()कि हालांकि गारंटी नहीं है कि एफडी लिखने योग्य है (या एक बाहरी उपयोगिता फोन (, अपने दृष्टिकोण में की तरह सफल होता है zsh/ perl...) करने के लिए fcntl())।

ध्यान दें कि bash(अधिकांश गोले की तरह), यदि आप (...)इसके बजाय का उपयोग करते हैं {...;}, तो यह एक अतिरिक्त प्रक्रिया का कांटा होगा। आप उपयोग कर सकते हैं:

if { true >&3; } 2<> /dev/null

इसके बजाय कांटे से बचने के लिए (बॉर्न शेल को छोड़कर जहां कंपाउंड कमांड को हमेशा पुनर्निर्देशित किया जाता है)। :इसके बजाय इसका उपयोग न करें trueक्योंकि यह एक विशेष बिलिन है, इसलिए पॉश अनुपालन मोड में बैश होने पर शेल बाहर निकलने का कारण होगा।

हालाँकि आप इसे छोटा कर सकते हैं:

if { >&3; } 2<> /dev/null

@mikeserve, re: आपका संपादन, इसके साथ क्या है <>? शेल अपने स्टाडर से पढ़ने नहीं जा रहा है, आप इसे रीड + राइट में क्यों खोलना चाहेंगे? आंतरिक के साथ क्या हुआ, इसका क्या मतलब है ? ?
स्टीफन चेज़लस

7

POSIX एप्लिकेशन उपयोग विवरण में आप निम्नलिखित पाएंगे:command

अवसर पर विशेष अंतर्निहित इन्स की विशेष विशेषताओं को दबाने के लिए कुछ फायदे हैं। उदाहरण के लिए:

command exec > unwritable-file

गैर-संवादात्मक स्क्रिप्ट को निरस्त करने का कारण नहीं बनता है, ताकि स्क्रिप्ट द्वारा आउटपुट स्थिति की जांच की जा सके।

यही कारण है कि आप बस कर सकते हैं:

if    command >&3
then  echo 3 is open >&3
else  ! echo 3 is not open
fi    2<>/dev/null

या ...

{ command >&3
  printf %s\\n%.0d  string "0$(($??8:0))" >&"$(($??1:3))"
} 2<>/dev/null

जो स्ट्रिंग लिखेगा उसके बाद एक \newline या तो stdout या 3 और फिर भी एक गैर-शून्य निकास स्थिति पर गुजरता है जब 3 खुला नहीं होता है क्योंकि $?हवाओं पर किया गया गणित ओक्टल 08 से % दशमलव में परिवर्तित करने में विफल रहता है लेकिन कुछ भी नहीं करता है अष्टदल ००

या ...

command exec >&3 || handle_it

लेकिन अगर आप उपयोग कर रहे हैं ksh93, तो आप कर सकते हैं:

fds

खुली फ़ाइल के विवरणों की सूची के लिए। -lवे कहाँ जाते हैं देखने के लिए जोड़ें ।


3

ओपन फाइल डिस्क्रिप्टर में पाया जा सकता है /proc/<pid>/fd। उदाहरण के लिए, उदाहरण के लिए, वर्तमान शेल के खुले फ़ाइल डिस्क्रिप्टर ls -l /proc/$$/fdजो आप जारी कर सकते हैं, जो आपको कुछ इस तरह देना चाहिए:

total 0
lrwx------ 1 testuser testuser 64 jun  1 09:11 0 -> /dev/pts/3
lrwx------ 1 testuser testuser 64 jun  1 09:11 1 -> /dev/pts/3
lrwx------ 1 testuser testuser 64 jun  1 09:11 2 -> /dev/pts/3
lrwx------ 1 testuser testuser 64 jun  1 09:39 255 -> /dev/pts/3

जब आप एक फ़ाइल का उपयोग कर खोलते हैं:

touch /tmp/myfile
exec 7</tmp/myfile

इसे नए द्वारा सूचीबद्ध किया जाना चाहिए ls -l /proc/$$/fd:

lr-x------ 1 testuser testuser 64 jun  1 09:11 7 -> /tmp/myfile

यदि आप फ़ाइल डिस्क्रिप्टर को फिर से बंद करते हैं तो exec 7>&-इसका उपयोग भी /proc/$$/fdअब सूचीबद्ध नहीं है।


2
यह सब लिनक्स के लिए काफी विशिष्ट है। FWIW।
lcd047

1
लिनक्स के साथ-साथ सोलारिस (10 और 11) पर भी इसका परीक्षण किया गया। अंतर यह है कि आपको pfiles <pid>यह देखने की आवश्यकता है कि ls -lलिनक्स पर कनेक्शन प्रदर्शित करते समय कौन सी फाइल डिस्क्रिप्टर किस फाइल से जुड़ी है ।
लैम्बर्ट

मुझे इसकी कॉम्पैक्टनेस [ -e /proc/$$/fd/3 ]पसंद है, लेकिन मैं procfs पर भरोसा नहीं करना पसंद करता हूं, क्योंकि यह FreeBSD में चित्रित किया गया है और संभवतः अन्य un * ces भी।
विटिको

1
मुझे उपयोग करने के विकल्प के लिए लाता है pfiles <pid>या lsof -p <pid>यह देखने के लिए कि कौन से फ़ाइल डिस्क्रिप्टर खुले हैं।
लैम्बर्ट

1
/procOpenBSD पर बिल्कुल मौजूद नहीं है। FreeBSD और NetBSD पर यह mountस्पष्ट रूप से होना चाहिए , और /proc/<PID>इसमें एक उपनिर्देशिका नहीं है fd
lcd047

3

आपकी चाल प्यारी लगती है; लेकिन एक मुहावरेदार तरीके के लिए मुझे आश्चर्य है कि आपने इसका उपयोग क्यों नहीं किया:

if ( exec 1>&3 ) 2>&-

यह वास्तव में, एक क्लीनर तरीका है।
विटिको

5
हालांकि यह एक उपधारा बनाता है जो सबसे अधिक गोले का मतलब है एक प्रक्रिया को फोर्क करना। यह गारंटी नहीं देता कि fd लेखनीय है। आप { true >&3; } 2> /dev/nullकांटे से बचने के लिए उपयोग कर सकते हैं । या { command exec >&3; } 2> /dev/nullयदि आप इसे करने के लिए stdout पुनर्निर्देशित करना चाहते हैं।
स्टीफन चेज़लस

@Stephane; @Witiko द्वारा खोजा गया सबस्क्रिप्शन ट्रिक वर्तमान परिवेश के फ़ाइल डिस्क्रिप्टर को पुनर्निर्देशन प्राप्त करने के लिए पुनर्निर्देशन का उपयोग करते समय प्रभावित नहीं करना था। - क्या आप "उल्लेखित एफडी" का उल्लेख कर सकते हैं?
Janis

2
{ true >&3; } 2> /dev/nullवर्तमान वातावरण को प्रभावित नहीं करेगा या कांटा (बॉर्न शेल को छोड़कर) नहीं करेगा। मेरा मतलब है कि (exec 1>&3) 2>&-रीड-ओनली मोड में एक fd ओपन के लिए सही है।
स्टीफन चेज़लस

1
execएक विशेष बिलिन होने पर शेल से बाहर निकल जाएगा यदि यह विफल हो जाता है (बैश के लिए, केवल जब POSIX अनुपालन मोड में)। command execरोकता है। trueएक विशेष बिलिन नहीं है। ध्यान दें कि execऔर command execवर्तमान वातावरण को प्रभावित करते हैं (यही कारण है कि मैंने कहा था कि यदि आप इसे करने के लिए stdout पुनर्निर्देशित करना चाहते हैं )।
स्टीफन चेज़लस

-1

यदि आप एक कम फोर्किंग समाधान में रुचि रखते हैं ताकि इसे दोहराने के लिए उपयोग किया जा सके, तो मैं इस फ़ंक्शन का सुझाव दूंगा:

checkfd () {
    exec 2> / dev / null
    अगर निष्पादन> & 3; फिर
        exec 1> / dev / tty
        गूंज "fd3 ठीक है"
    अन्य
        इको "fd3 KO"
    फाई
    exec 2> / dev / tty
}

और यहाँ है कि यह एक के साथ पैदा करता है zsh:

$ चेकफद            
fd3 केओ
$ चेकफड 3> / देव / अशक्त
fd3 ठीक है
$

अधिकांश गोले खोल exec >&3को मार देंगे जब 3 खुला नहीं होगा।
मिकसेर

कम से कम यह zshऔर पर काम कर रहा है bash। क्या आप वह शेल प्रदान कर सकते हैं जिस पर विफल होने के execकारण ए exit?
दान

हाँ। में bashकरना set -o posixऔर फिर कोशिश करें। में zsh... मुझे लगता है कि यह एनवी संस्करण POSIX_BUILTINSको एक शून्य-मूल्य पर सेट करने की बात है - लेकिन मैं ऑफहैंड को भूल जाता हूं। किसी भी मामले में, zshएक शेल नहीं है जो पोसिक्स अनुपालन का प्रयास करता है, और इसलिए यह निश्चित रूप से गैर-मानक है। उन दोनों गोले अनुकूलता के लिए अनुकूल हैं जो कुछ मानते हैं कि सुविधा है।
मिकसेर

यह सादे बॉर्न शेल पर भी काम कर रहा है।
दान

बैश में, set -o posixएक कोशिश के साथ सफल है।
दान

-1

यह सुपर आसान लगता है (टिप्पणी देखें):

[ -r /proc/$$/fd/$FD ] && echo "File descriptor $FD is readable"
[ -w /proc/$$/fd/$FD ] && echo "File descriptor $FD is writable"

एक अतिरिक्त के रूप में ... [-r फ़ाइल] परीक्षण यह इंगित नहीं करता है कि क्या कोई डेटा वास्तव में पढ़ने का इंतजार कर रहा है (/ देव / अशक्त इस परीक्षा को पास करता है (टिप्पणियां देखें))।

[ -r /proc/$$/fd/4 ] \
  && [ read -t 0.0001 -N 0 <&4 ] \
  && echo "Data is waiting to be read from file descriptor 4"

टाइमआउट तर्क (पढ़ने के लिए) के लिए कुछ छोटी संख्या या डेटा की आवश्यकता होती है जिसे कुछ गणना की आवश्यकता हो सकती है। पठनीय परीक्षण ([-r फ़ाइल]) की आवश्यकता होती है या यदि फ़ाइल पठनीय नहीं है, तो पढ़ा गया कमांड बम होगा। यह वास्तव में किसी भी डेटा को नहीं पढ़ेगा क्योंकि बाइट की संख्या शून्य है (पढ़ें-एन 0)।


यदि आप एक लिनक्स सिस्टम को मानने जा रहे हैं, तो आप बस एक नज़र डाल सकते हैं /proc/<pid>/fdinfo/<fd>, जो सभी खुली फाइलों के मोड को नीचे flags:देखती है - यहाँ देखें । आपके 2 भाग के लिए (यहां तक ​​कि चकाचौंध की गलती को ठीक करने के बाद भी): read -t .1 -N0 <&4यह नहीं बताएगा कि क्या एफडी 4 पर पढ़ने के लिए डेटा है: आप इसके साथ प्रयास करें 4</dev/null
मॉसवी

और निश्चित रूप से, आपको [ -r /proc/$$/fd/$FD ]यह नहीं बताता है कि क्या फाइल डिस्क्रिप्टर $FDपढ़ने योग्य है, लेकिन अगर यह जिस फाइल से खुला था, वह फिर से खुल सकती है , पढ़ने के लिए एक और फाइल डिस्क्रिप्टर के साथ:exec 7>/tmp/foo; [ -r /proc/$$/fd/7 ] && echo fd 7 can be read from && cat <&7
मस्वी

-1

यह सवाल काफी पुराना है - लेकिन वैसे भी - बस क्यों नहीं बिल्डरों का उपयोग करते हैं?

for i in {0..5} ; do if [ -t $i ]; then echo "$i is a valid FD"; else echo "$i is INVALID FD"; fi; done

आउटपुट:

0 is a valid FD
1 is a valid FD
2 is a valid FD
3 is INVALID FD
4 is INVALID FD
5 is INVALID FD

तो, सवाल का जवाब देने के लिए - सुझाव देंगे:

if [ -t 3 ]; then
  # File descriptor 3 is open
else
  # File descriptor 3 is not open
fi

-tयदि फ़ाइल डिस्क्रिप्टर मान्य है, तो यह परीक्षण नहीं करता है, लेकिन यदि यह एक ट्टी से जुड़ा है। echo yup |अपनी स्क्रिप्ट के लिए एक प्राथमिकता दें , और कहेंगे कि 0 is INVALID FDवास्तव में, यह बहुत ही मान्य fd, एक पाइप है।
मॉसवी
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.