सभी फ़ाइल डिस्क्रिप्टर को bash में बंद करें


13

क्या पहले से उनकी स्पष्ट सूची के बिना सभी खुले फ़ाइल विवरणकों को बंद करने का एक तरीका है?


4
सभी फाइल डिस्क्रिप्टर में से कौन सा ? हर प्रक्रिया में कुछ खुला है।
वॉरेन यंग

"सभी खुले फ़ाइल विवरणक" क्या हैं? 0, 1, और 2? या आपके पास और भी कई हैं? यदि हां, तो वे कहां से आए थे?
यू विंडल

जब स्क्रिप्ट खत्म हो जाती है तो फ़ाइल डिस्क्रिप्टर स्वचालित रूप से बंद नहीं होते हैं?
जर्नो

जवाबों:


15

शाब्दिक रूप से उत्तर देने के लिए, सभी खुले फ़ाइल विवरणों को बंद करने के लिए bash:

for fd in $(ls /proc/$$/fd); do
  eval "exec $fd>&-"
done

हालांकि यह वास्तव में एक अच्छा विचार नहीं है क्योंकि यह मूल फ़ाइल विवरणों को बंद कर देगा जो इनपुट और आउटपुट के लिए शेल की आवश्यकता है। यदि आप ऐसा करते हैं, तो आपके द्वारा चलाए जाने वाले कार्यक्रमों में से कोई भी टर्मिनल पर अपना आउटपुट प्रदर्शित नहीं करेगा (जब तक कि वे ttyडिवाइस पर सीधे नहीं लिखते )। यदि मेरे परीक्षणों को बंद करने stdin( exec 0>&-) में तथ्य सिर्फ एक इंटरैक्टिव शेल से बाहर निकलने का कारण बनता है।

जो आप वास्तव में करना चाह रहे हैं वह सभी फ़ाइल विवरणों को बंद करने के लिए है जो शेल के मूल ऑपरेशन का हिस्सा नहीं हैं। ये हैं 0 के लिए stdin, 1 के लिए stdoutऔर 2 के लिए stderr। इसके ऊपर कुछ गोले डिफ़ॉल्ट रूप से अन्य फ़ाइल डिस्क्रिप्टर को खोलते हैं। में bash, उदाहरण के लिए, आप 255 (भी टर्मिनल आई / ओ के लिए) और में है dash10 मेरे पास है, जो अंक के /dev/ttyबजाय विशिष्ट से tty/ ptsउपकरण टर्मिनल का उपयोग कर रहा है। 0, 1, 2 और 255 के अलावा सब कुछ बंद करने के लिए bash:

for fd in $(ls /proc/$$/fd); do
  case "$fd" in
    0|1|2|255)
      ;;
    *)
      eval "exec $fd>&-"
      ;;
  esac
done

यह भी ध्यान रखें कि evalजब फ़ाइल वर्णनकर्ता एक चर में निहित पुनः निर्देशित की आवश्यकता है, नहीं तो bashचर का विस्तार होगा, लेकिन यह आदेश के हिस्से पर विचार (इस मामले में यह करने की कोशिश करेगा execआदेश 0या 1या जो भी फ़ाइल वर्णनकर्ता आप पास करने की कोशिश कर रहे हैं)।

नोट: इसके अलावा ls(जैसे /proc/$$/fd/*) के बजाय एक ग्लोब का उपयोग करने से ग्लोब के लिए एक अतिरिक्त फ़ाइल डिस्क्रिप्टर खुलता है, इसलिए lsयहां सबसे अच्छा समाधान लगता है।

अपडेट करें

की पोर्टेबिलिटी के बारे में अधिक जानकारी के लिए /proc/$$/fd, कृपया फ़ाइल डिस्क्रिप्टर लिंक की पोर्टेबिलिटी देखें । यदि /proc/$$/fdअनुपलब्ध है, तो $(ls /proc/$$/fd), lsof(यदि वह उपलब्ध है) का उपयोग करने के लिए प्रतिस्थापन में एक गिरावट होगी $(lsof -p $$ -Ff | grep f[0-9] | cut -c 2-)


/procकेवल लिनक्स के तहत उपलब्ध है।
चेपनर

4
@ यदि आप कहते हैं कि आप /proc/PID/fdबहुत पोर्टेबल नहीं हैं, तो आप सही होंगे । लेकिन यह कहना कि /procकेवल लिनक्स के तहत उपलब्ध है एक सही बयान नहीं है।
ग्रीम

कुछ वेबसाइटें <&-फॉर्म का उपयोग करती हैं , क्या यह कोई अलग / आवश्यक है?
लोरेंजो पिस्टन

@LorenzoPistone, डिस्क्रिप्टर को बंद करते समय दिशा को कोई फर्क नहीं पड़ता है, इसलिए या तो फॉर्म का उपयोग किया जा सकता है।
ग्रीम

5

बैश (4.1 और आगे, वर्ष 2009 और बाद के) के हाल के संस्करणों में आप शेल वर्णक का उपयोग करके फ़ाइल डिस्क्रिप्टर को बंद करने के लिए निर्दिष्ट कर सकते हैं:

for fd in $(ls /proc/$$/fd/); do
    [ $fd -gt 2 ] && exec {fd}<&-
done

फीचर कोर्न शेल में पहले से ही था (1993 के बाद से?) लेकिन जाहिर तौर पर बैश में अपना रास्ता बनाने में कुछ समय लगा।


1

वर्तमान शेल के i / o / e को छोड़कर सभी फ़ाइल डिस्क्रिप्टर को साफ़ करें, लेकिन प्रदान की गई दलीलों को भी शामिल नहीं करता है

clear_fds() {
for fd in $(compgen -G "/proc/$BASHPID/fd/*"); do
    fd=${fd/*\/}
        if [[ ! " $* " =~ " ${fd} " ]]; then
            case "$fd" in
                0|1|2|255)
                ;;
                *)
                    eval "exec $fd>&-"
                    ;;
            esac
        fi
done
}

0

"Eval" के बिना एक और तरीका है, फॉर्म का उपयोग करना है:

$ exec {var_a}>> file.txt
$ echo $var_a
10
$ ls -l /proc/self/fd/10
l-wx------ 1 0 0 64 Dec 11 18:32 /proc/self/fd/10 -> /run/user/0/tmp/file.txt
$ echo "aaaaa" >&$var_a
$ cat file.txt
aaaaa
$ exec {var_a}>&-
$ ls /proc/self/fd/10
ls: cannot access '/proc/self/fd/10': No such file or directory

लेकिन यह सभी फ़ाइल डिस्क्रिप्टर को बंद नहीं करता है ।
जी-मैन का कहना है कि 'मोनिका' को

वास्तव में। आपको पिछले उत्तरों में बताए गए एक लूप में निष्पादित करना होगा ... यह केवल इस तथ्य को इंगित करना था कि "eval" यहां अनिवार्य नहीं है और इसे खोलने के बजाय हम इसे बंद करने के लिए एक ही तर्क रख सकते हैं। । मैन पेज वास्तव में इस बारे में स्पष्ट नहीं हैं ...
डेविड डीजी

0

नहीं। कर्नेल एक समय में केवल एक एफडी को बंद कर सकता है, और bash में FD के लिए "समूह कमांड" नहीं है।

for fd in $(ls -1 /proc/27343/fd); do echo exec $fd">&"-; done

echoऔर निकालें" परीक्षण बाद ।

यदि यह शेल के लिए नहीं है, लेकिन कमांड चलाने के लिए है तो आप उपयोग कर सकते हैं nohup


2
फ़ाइल डिस्क्रिप्टर का उपयोग >&-एक पैरामीटर नहीं हो सकता है; पुनर्निर्देशन को पैरामीटर विस्तार से पहले पार्स किया जाता है।
चेपनर

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