2012-03-29 11 views
36

के लिए स्पष्टीकरण Bash Reference Manual से की आवश्यकता है मैं निम्नलिखित exec के बारे में पार्टी builtin आदेश मिलता है:लिनक्स बैश builtin कार्यकारी आदेश व्यवहार

तो आदेश आपूर्ति की जाती है, यह एक नई प्रक्रिया बनाने के बिना खोल बदल देता है।

#!/bin/bash 
exec ls; 
echo 123; 
exit 0 

यह मार डाला मैं यह मिल गया,:

अब मैं निम्नलिखित bash स्क्रिप्ट है

cleanup.sh ex1.bash file.bash file.bash~ output.log 
(files from the current directory) 

अब, अगर मैं इस स्क्रिप्ट है:

#!/bin/bash 
exec ls | cat 
echo 123 
exit 0 

मुझे निम्न आउटपुट मिलता है:

cleanup.sh 
ex1.bash 
file.bash 
file.bash~ 
output.log 
123 

मेरा प्रश्न है:

हैं जब execशुरू हो जाती है यह एक नई प्रक्रिया, कारण है कि जब | cat डाल बनाए बिना खोल बदल देता है, echo 123 छपा है, लेकिन इसके बिना, ऐसा नहीं है। इसलिए, अगर कोई इस व्यवहार के तर्क को समझा सकता है तो मैं खुश रहूंगा।

धन्यवाद।

संपादित करें: @torek प्रतिक्रिया के बाद, मैं एक और भी कठिन मिल व्यवहार की व्याख्या करने के लिए:

1. exec ls>out आदेश out फ़ाइल बनाता है और यह ls के आदेश परिणाम में डाल;

2. exec ls>out1 ls>out2 केवल फाइलें बनाता है, लेकिन किसी भी परिणाम के अंदर नहीं डालता है। यदि आदेश सुझाए गए अनुसार काम करता है, तो मुझे लगता है कि कमांड नंबर 2 के पास कमांड नंबर 1 के समान परिणाम होना चाहिए (और भी, मुझे लगता है कि इसे out2 फ़ाइल नहीं बनाई जानी चाहिए)।

+4

मैंने कुछ सीखा! – blueshift

+1

आप 'exec' पर लिंक सी 'exec' फ़ंक्शन है। आप जो परीक्षण कर रहे हैं वह 'bash'' exec' buildin है। वे एक जैसे नहीं हैं। Www.gnu.org/software/bash/manual/bashref.html –

+0

@ जे -16 एसडीआईजेड को सुझाए गए अनुसार सही किया गया है, लेकिन समस्या – artaxerxe

उत्तर

38

इस विशेष मामले में, आपके पास पाइपलाइन में exec है। पाइपलाइन कमांड की श्रृंखला को निष्पादित करने के लिए, खोल को प्रारंभिक रूप से कांटा बनाना चाहिए, जिससे उप-खोल हो। (विशेष रूप से इसे पाइप, फिर कांटा बनाना है, ताकि पाइप के "बाईं ओर" चलने वाली सभी चीज़ों को पाइप के "दाईं ओर" जो भी हो, उसका आउटपुट भेजा जा सके।)

यह देखने के लिए तथ्य यह है क्या हो रहा है में है, की तुलना:

साथ
{ ls; echo this too; } | cat 

:

{ exec ls; echo this too; } | cat 

पूर्व रन ls उप खोल से बाहर निकले बिना, ताकि इस उप-खोल इसलिए अभी भी चारों ओर echo चलाने के लिए है । उत्तरार्द्ध उप-शेल छोड़कर ls चलाता है, जो अब echo करने के लिए नहीं है, और this too मुद्रित नहीं है।

(घुंघराले-ब्रेसिज़ { cmd1; cmd2; } के उपयोग के सामान्य रूप से उप खोल कांटा कार्रवाई है कि आप कोष्ठकों (cmd1; cmd2) साथ मिल को दबा है, लेकिन एक पाइप के मामले में, कांटा "मजबूर" है, क्योंकि यह थे।)

वर्तमान खोल का पुनर्निर्देशन केवल तभी होता है जब exec शब्द के बाद "चलाने के लिए कुछ नहीं" होता है। इस प्रकार, उदाहरण के लिए, exec >stdout 4<input 5>>append वर्तमान खोल को संशोधित करता है, लेकिन exec foo >stdout 4<input 5>>append निष्पादन आदेश foo करने का प्रयास करता है। [नोट: यह कड़ाई से सटीक नहीं है; परिशिष्ट देखें।]

दिलचस्प है, एक इंटरैक्टिव खोल में, के बाद exec foo >output विफल रहता है कोई आदेश foo, चारों ओर खोल लाठी है वहाँ क्योंकि, लेकिन stdout output दायर करने के लिए निर्देशित कर दिये रहता है। @ Pumbaa80 को टोपी के एक टिप के साथ (आप exec >/dev/tty साथ ठीक हो सकता है एक स्क्रिप्ट में, exec foo की विफलता स्क्रिप्ट समाप्त हो जाता है।।)


, यहाँ कुछ और भी उदाहरण है:

#! /bin/bash 
shopt -s execfail 
exec ls | cat -E 
echo this goes to stdout 
echo this goes to stderr 1>&2 

(ध्यान दें: cat -E मेरे सामान्य cat -vET से नीचे सरलीकृत किया गया है, जो कि "मुझे पहचानने योग्य तरीके से गैर-प्रिंटिंग वर्ण देखने दें" के लिए मेरा आसान तरीका है)। जब यह स्क्रिप्ट चलती है, ls से आउटपुट cat -E लागू होता है (लिनक्स पर यह $ 200 के रूप में दिखाई देने वाली अंतराल को बनाता है), लेकिन स्टडआउट और स्टेडर (शेष दो पंक्तियों पर) को भेजा गया आउटपुट पुनर्निर्देशित नहीं है । | cat -E से > out बदलें और, स्क्रिप्ट चलाने के बाद, फ़ाइल out की सामग्री का निरीक्षण करें: अंतिम दो echo एस वहां नहीं हैं।

अब ls से foo (या कुछ अन्य आदेश जो नहीं मिलेगा) को बदलें और स्क्रिप्ट को फिर से चलाएं। इस बार उत्पादन होता है:

$ ./demo.sh 
./demo.sh: line 3: exec: foo: not found 
this goes to stderr 

और फ़ाइल out अब पहले echo लाइन द्वारा उत्पादित सामग्री है।

यह exec "वास्तव में करता है" जितना संभव हो उतना स्पष्ट (लेकिन अधिक स्पष्ट नहीं है, क्योंकि अल्बर्ट आइंस्टीन ने इसे नहीं रखा :-))।

आम तौर पर, जब खोल "सरल कमांड" निष्पादित करने के लिए चला जाता है (सटीक परिभाषा के लिए मैन्युअल पृष्ठ देखें, लेकिन यह विशेष रूप से "पाइपलाइन" में कमांड को बहिष्कृत करता है), यह किसी भी I/O पुनर्निर्देशन संचालन को निर्दिष्ट करता है <, >, और इसलिए आवश्यक फ़ाइलों को खोलकर। फिर खोल fork (या कुछ समकक्ष लेकिन अधिक कुशल संस्करण जैसे vfork या clone अंतर्निहित ओएस, कॉन्फ़िगरेशन इत्यादि के आधार पर), और, बाल प्रक्रिया में, खुली फ़ाइल डिस्क्रिप्टर (dup2 कॉल या समकक्ष का उपयोग करके) को पुन: व्यवस्थित करता है। वांछित अंतिम व्यवस्था: > out खुला वर्णनकर्ता चाल एफडी 1-stdout-जबकि 6> out एफडी 6.

आप exec कीवर्ड, हालांकि, खोल को दबा fork कदम निर्दिष्ट करते हैं खुला वर्णनकर्ता ले जाता है। यह सभी फाइल खोलने और फ़ाइल-डिस्क्रिप्टर-सामान्य रूप से पुनर्व्यवस्थित करता है, लेकिन इस बार, यह किसी भी और सभी बाद के आदेश को प्रभावित करता है। अंत में, सभी पुनर्निर्देशन करने के बाद, शेल execve() (सिस्टम-कॉल भावना में) आदेश देता है, यदि कोई है तो आदेश।यदि कोई आदेश नहीं है, या execve() कॉल और विफल रहता है तो खोल चलाना जारी रहता है (इंटरैक्टिव है या आपने execfail सेट किया है), शैल सैनिकों पर। यदि execve() सफल होता है, तो शेल अब मौजूद नहीं है, जिसे नए कमांड द्वारा प्रतिस्थापित किया गया है। यदि execfail अनसेट है और खोल इंटरैक्टिव नहीं है, तो खोल निकलता है।

(वहाँ भी command_not_found_handle खोल समारोह का जोड़ा जटिलता है: बैश के exec इसे चलाने को दबाने के लिए परीक्षण के परिणाम के आधार पर, लगता है सामान्य रूप में exec कीवर्ड, बनाता खोल अपनी ही काम करता है, यानी पर नहीं लग रही है यदि आप एक है। खोल समारोह च, f एक साधारण आदेश के रूप में चल खोल समारोह चलाता है, (f) जो इसे एक उप खोल में चलाता है, लेकिन इस पर (exec f) स्किप के चल रहा है के रूप में।)


क्यों ls>out1 ls>out2 दो फ़ाइलें (के साथ या एक के बिना बनाता है के रूप में exec), यह काफी आसान है: खोल प्रत्येक पुनर्निर्देशन को खोलता है, और फिर फ़ाइल वर्णनकर्ताओं को स्थानांतरित करने के लिए dup2 का उपयोग करता है। यदि आपके पास दो सामान्य > रीडायरेक्ट हैं, तो खोल दोनों खुलता है, पहले को एफडी 1 (stdout) में ले जाता है, फिर दूसरे को एफडी 1 (फिर से स्टडआउट) में ले जाता है, प्रक्रिया में पहले बंद कर देता है। अंत में, यह ls ls चलाता है, क्योंकि >out1 >out2 को हटाने के बाद यह शेष है। जब तक ls नाम की कोई फ़ाइल नहीं है, ls कमांड stderr की शिकायत करता है, और stdout के लिए कुछ भी नहीं लिखता है।

+1

बनी हुई है (गैर-) इंटरैक्टिव शैल के लिए, मैनपेज कहता है "अगर' कमांड 'नहीं हो सकता कुछ कारणों से निष्पादित किया जाना चाहिए, एक गैर-इंटरैक्टिव खोल बाहर निकलता है, जब तक कि खोल विकल्प 'execfail' सक्षम नहीं होता है, इस स्थिति में यह विफलता देता है। एक इंटरैक्टिव शैल रिटर्न विफलता " – user123444555621

+0

@torek प्रश्न – artaxerxe

+0

@ Pumbaa80 में EDIT भाग को देखें : बहुत अच्छा; इससे "निष्पादन कैसे कार्य करता है" स्पष्ट करने में मदद करता है। मैं अपने जवाब में एक नोट जोड़ दूंगा। – torek