जब मैं अपने शेल में फ़ाइल निष्पादित करता हूं तो वास्तव में क्या होता है?


32

इसलिए, मुझे लगा कि मुझे इस बारे में अच्छी समझ है, लेकिन बस एक परीक्षण चला (एक बातचीत के जवाब में जहां मैं किसी से असहमत था) और पाया कि मेरी समझ त्रुटिपूर्ण है ...

में संभव के रूप में ज्यादा विस्तार के रूप में वास्तव में क्या होता है क्या जब मैं अपने खोल में एक फ़ाइल को अंजाम? मेरा क्या मतलब है, अगर मैं टाइप करता हूं: ./somefile some argumentsमेरे शेल में और प्रेस रिटर्न (और somefileसीडब्ल्यूडी में मौजूद है, और मैंने + पर अनुमतियों को पढ़ लिया है somefile) तो हुड के नीचे क्या होता है?

मुझे लगा कि उत्तर था:

  1. खोल एक syscall बनाने के लिए exec, मार्ग से गुजर रहा हैsomefile
  2. कर्नेल जांचता है somefileऔर यह निर्धारित करने के लिए फ़ाइल की जादुई संख्या को देखता है कि क्या यह एक प्रारूप है जिसे प्रोसेसर संभाल सकता है
  3. यदि जादू संख्या इंगित करती है कि फ़ाइल एक प्रारूप में है तो प्रोसेसर निष्पादित कर सकता है, फिर
    1. एक नई प्रक्रिया बनाई गई है (प्रक्रिया तालिका में एक प्रविष्टि के साथ)
    2. somefileको पढ़ा जाता है / स्मृति में मैप किया जाता है। एक ढेर बन जाता है और निष्पादन के कोड के प्रवेश बिंदु करने के लिए कूदता है somefile, साथ ARGV(एक पैरामीटर की एक सरणी के लिए शुरू char**, ["some","arguments"])
  4. यदि मैजिक नंबर एक शेबंग है, तो exec()ऊपर के रूप में एक नई प्रक्रिया पैदा करता है, लेकिन निष्पादन योग्य का उपयोग शेबबैंग द्वारा संदर्भित दुभाषिया होता है (जैसे /bin/bashया /bin/perl) और somefileपास किया जाता हैSTDIN
  5. यदि फ़ाइल में कोई वैध मैजिक नंबर नहीं है, तो "अमान्य फ़ाइल (खराब मैजिक नंबर): त्रुटि प्रारूप त्रुटि" जैसी त्रुटि होती है

हालाँकि किसी ने मुझे बताया कि अगर फ़ाइल सादा पाठ है, तो शेल कमांड निष्पादित करने की कोशिश करता है (जैसे कि मैंने टाइप किया था bash somefile)। मुझे इस पर विश्वास नहीं हुआ, लेकिन मैंने अभी इसकी कोशिश की, और यह सही था। इसलिए मुझे स्पष्ट रूप से कुछ गलतफहमी है कि वास्तव में यहाँ क्या होता है, और यांत्रिकी को समझना चाहते हैं।

जब मैं अपने शेल में फ़ाइल निष्पादित करता हूं तो वास्तव में क्या होता है? (जैसा कि विस्तार में उचित है ...)


समझने की पूरी गहराई के लिए स्रोत कोड को देखने के लिए कोई सही विकल्प नहीं है ।
वाइल्डकार्ड

1
@Wildcard यह वही है जो मैं अभी कर रहा हूं, वास्तव में :-) अगर मैं कर सकता हूं, तो मैं अपने खुद के सवाल का जवाब दूंगा
जोश

1
source somefile./somefileहालाँकि, एक नई प्रक्रिया से अलग किया जा रहा है , हालांकि।
थ्रू

@ हां, मैं सहमत हूं। लेकिन मुझे नहीं लगता था कि अगर फाइल में मैजिक नंबर नहीं होता है तो ./somefileकमांड को निष्पादित करने के लिए बैश होगा somefile। मैंने सोचा कि यह सिर्फ एक त्रुटि प्रदर्शित करेगा, और इसके बजाय यह प्रभावी रूप से प्रकट होता हैsource somefile
जोश

मैं फिर से गलत हूं, मैं इस बात की पुष्टि कर सकता हूं कि यदि somefileकोई पाठ फ़ाइल है, तो यदि मैं इसे निष्पादित करने का प्रयास करता हूं, तो एक नया शेल खोल दिया जाता है। echo $$यदि मैं इसे स्रोत के रूप में निष्पादित करता हूं तो एक फ़ाइल अलग तरह से व्यवहार करती है।
जोश

जवाबों:


31

लिनक्स पर "प्रोग्राम कैसे चलते हैं" का निश्चित उत्तर , LWN.net पर लेखों की जोड़ी है , जिसका शीर्षक है, आश्चर्यजनक रूप से पर्याप्त, कैसे प्रोग्राम चलते हैं और प्रोग्राम कैसे चलते हैं: ELF बायनेरिज़ । पहला लेख स्क्रिप्ट को संक्षेप में संबोधित करता है। (कड़ाई से निश्चित उत्तर बोलना स्रोत कोड में है, लेकिन ये लेख स्रोत कोड के लिंक को पढ़ने और प्रदान करने में आसान हैं।)

थोड़ा सा प्रयोग यह दर्शाता है कि आप बहुत हद तक सही हो गए हैं, और यह कि एक फाइल को निष्पादित करने के लिए कमांड की एक सरल सूची है, जिसमें एक शेल्फ़ के बिना शेल को संभालने की आवश्यकता है। Execve (2) मैनपेज एक परीक्षण कार्यक्रम के लिए स्रोत कोड शामिल हैं, execve; हम इसका उपयोग उस शेल के बिना देखने के लिए करेंगे। सबसे पहले, एक टेस्टस्क्रिप्ट लिखिए testscr1, जिसमें

#!/bin/sh

pstree

और एक अन्य testscr2, केवल युक्त

pstree

उन दोनों को निष्पादन योग्य बनाएं, और सत्यापित करें कि वे दोनों एक शेल से चलते हैं:

chmod u+x testscr[12]
./testscr1 | less
./testscr2 | less

अब पुन: प्रयास करें, प्रयोग करके execve(यह मानकर कि आपने इसे वर्तमान निर्देशिका में बनाया है):

./execve ./testscr1
./execve ./testscr2

testscr1अभी भी चलाता है, लेकिन testscr2पैदा करता है

execve: Exec format error

इससे पता चलता है कि शेल testscr2अलग तरीके से हैंडल करता है । यह स्क्रिप्ट को स्वयं संसाधित नहीं करता है, हालांकि यह अभी भी /bin/shऐसा करने के लिए उपयोग करता है; इस पाइप द्वारा सत्यापित किया जा सकता testscr2करने के लिए less:

./testscr2 | less -ppstree

अपने सिस्टम पर, मुझे मिलता है

    |-gnome-terminal--+-4*[zsh]
    |                 |-zsh-+-less
    |                 |     `-sh---pstree

जैसा कि आप देख सकते हैं, वहाँ शेल मैं उपयोग कर रहा था zsh, जो शुरू हुआ less, और स्क्रिप्ट चलाने के लिए दूसरा शेल, प्लेन sh( dashमेरे सिस्टम पर), जो चला pstree। इसमें इसके zshद्वारा नियंत्रित किया जाता zexecveहै Src/exec.c: शेल execve(2)कमांड को चलाने का प्रयास करता है, और यदि वह विफल हो जाता है, तो यह फाइल को यह देखने के लिए पढ़ता है कि क्या इसमें एक शेलबैंग है, इसे तदनुसार संसाधित करना (जो कर्नेल भी किया होगा), और यदि वह यह तब तक विफल रहता है shजब तक वह फ़ाइल से कोई भी शून्य बाइट नहीं पढ़ता, फ़ाइल को चलाने की कोशिश करता है :

        for (t0 = 0; t0 != ct; t0++)
            if (!execvebuf[t0])
                break;
        if (t0 == ct) {
            argv[-1] = "sh";
            winch_unblock();
            execve("/bin/sh", argv - 1, newenvp);
        }

bashएक ही व्यवहार, execute_cmd.cएक सहायक टिप्पणी के साथ लागू किया गया है (जैसा कि टैल्ज़िन द्वारा बताया गया है ):

एक साधारण आदेश निष्पादित करें जो उम्मीद है कि डिस्क फ़ाइल में कहीं परिभाषित है।

  1. fork ()
  2. पाइप कनेक्ट करें
  3. आज्ञा देखो
  4. पुनर्निर्देशन करें
  5. execve ()
  6. यदि execveविफल हुआ, तो देखें कि क्या फ़ाइल में निष्पादन योग्य मोड सेट है। यदि ऐसा है, और यह एक निर्देशिका नहीं है, तो एक शेल स्क्रिप्ट के रूप में इसकी सामग्री को निष्पादित करें।

POSIX के रूप में जाना कार्यों का एक सेट, को परिभाषित करता है कार्यों , जो चादर और इस कार्यक्षमता भी प्रदान करते हैं; देख muru की जानकारी के लिए इस सवाल का जवाब। लिनक्स पर कम से कम ये कार्य C लाइब्रेरी द्वारा कार्यान्वित किए जाते हैं, कर्नेल द्वारा नहीं।exec(3)execve(2)


यह शानदार है और इसमें वह विवरण है जिसकी मुझे तलाश थी, धन्यवाद!
जोश

12

भाग में, यह उस विशेष execपारिवारिक फ़ंक्शन पर निर्भर करता है जिसका उपयोग किया जाता है। execve, जैसा कि स्टीफन किट ने विस्तार से दिखाया है, केवल सही द्विआधारी प्रारूप या स्क्रिप्ट में फाइलें चलाता है जो एक उचित शेबंग के साथ शुरू होता है।

हालाँकि , execlpऔर execvpएक कदम आगे बढ़ें: यदि शेलबंग सही नहीं था, तो फ़ाइल को /bin/shलिनक्स पर निष्पादित किया जाता है । से man 3 exec:

Special semantics for execlp() and execvp()
   The execlp(), execvp(), and execvpe() functions duplicate the actions
   of the shell in searching for an executable file if the specified
   filename does not contain a slash (/) character.

   If the header of a file isn't recognized (the attempted execve(2)
   failed with the error ENOEXEC), these functions will execute the
   shell (/bin/sh) with the path of the file as its first argument.  (If
   this attempt fails, no further searching is done.)

यह POSIX (जोर मेरा) द्वारा समर्थित है :

मानक डेवलपर्स द्वारा नोट किए गए भ्रम का एक संभावित स्रोत यह है कि एक प्रक्रिया छवि फ़ाइल की सामग्री कार्यों के निष्पादन परिवार के व्यवहार को कैसे प्रभावित करती है। निम्नलिखित क्रियाओं का वर्णन है:

  1. यदि इस सिस्टम के लिए प्रक्रिया छवि फ़ाइल एक वैध निष्पादन योग्य है (एक प्रारूप में जो निष्पादन योग्य और वैध है और उपयुक्त विशेषाधिकार हैं), तो सिस्टम फ़ाइल को निष्पादित करता है।

  2. यदि प्रक्रिया छवि फ़ाइल में उचित विशेषाधिकार हैं और एक प्रारूप में है जो निष्पादन योग्य है, लेकिन इस प्रणाली के लिए मान्य नहीं है (जैसे कि किसी अन्य वास्तुकला के लिए एक मान्यता प्राप्त बाइनरी), तो यह एक त्रुटि है और इरानो [EINVAL] पर सेट है (बाद में देखें [EINVAL] पर)।

  3. यदि प्रक्रिया छवि फ़ाइल में उचित विशेषाधिकार हैं, लेकिन अन्यथा मान्यता प्राप्त नहीं है:

    1. यदि यह निष्पादित () या निष्पादित () करने के लिए एक कॉल है, तो वे एक कमांड दुभाषिया को यह कहते हुए आमंत्रित करते हैं कि प्रक्रिया छवि फ़ाइल एक शेल स्क्रिप्ट है।

    2. यदि यह निष्पादित () या निष्पादित () करने के लिए कॉल नहीं है, तो एक त्रुटि होती है और इरानो [ENOEXEC] पर सेट होता है।

यह निर्दिष्ट नहीं करता है कि कमांड दुभाषिया कैसे प्राप्त किया जाता है, इसलिए, लेकिन यह निर्दिष्ट नहीं करता है कि एक त्रुटि दी जानी है। इसलिए, मेरा अनुमान है कि लिनक्स देवों ने ऐसी फ़ाइलों को चलाने की अनुमति दी /bin/shथी (या यह पहले से ही एक सामान्य अभ्यास था और वे सिर्फ सूट का पालन करते थे)।

FWIW, FreeBSD मैनपेज के लिएexec(3) भी इसी तरह के व्यवहार का उल्लेख करता है:

 Some of these functions have special semantics.

 The functions execlp(), execvp(), and execvP() will duplicate the actions
 of the shell in searching for an executable file if the specified file
 name does not contain a slash ``/'' character. 
 If the header of a file is not recognized (the attempted execve()
 returned ENOEXEC), these functions will execute the shell with the path
 of the file as its first argument.  (If this attempt fails, no further
 searching is done.)

AFAICT, हालांकि, पर्यावरण पर महीन नियंत्रण के लिए कोई सामान्य खोल execlpया execvpसीधे उपयोग नहीं किया गया है। वे सभी एक ही तर्क का उपयोग करके लागू करते हैं execve


3
मैं भी लिनक्स पर कम से कम है कि जोड़ने के लिए, चाहते हैं execl, execlp, execle, execv, execvpऔर execvpeकरने के लिए सभी सामने के छोर हैं execvesyscall; पूर्व को सी लाइब्रेरी द्वारा प्रदान किया जाता है, कर्नेल केवल execve(और execveatआजकल) के बारे में जानता है ।
स्टीफन किट

यही कारण है कि बताते हैं @StephenKitt कारण है कि मैं नहीं पर man7.org के खंड 2. उन कार्यों के लिए एक मैनपेज मिल सकता है
muru

6

यह स्टीफन किट के जवाब के अलावा हो सकता है, bashफ़ाइल में स्रोत से एक टिप्पणी के रूप में execute_cmd.c:

एक साधारण आदेश निष्पादित करें जो उम्मीद है कि डिस्क फ़ाइल में कहीं परिभाषित है।

1. fork ()
2. connect pipes
3. look up the command
4. do redirections
5. execve ()
6. If the execve failed, see if the file has executable mode set.  

यदि ऐसा है, और यह एक निर्देशिका नहीं है, तो एक शेल स्क्रिप्ट के रूप में इसकी सामग्री को निष्पादित करें।


0

इसे शेल स्क्रिप्ट के रूप में निष्पादित किया जाता है, यह खट्टा नहीं होता है (उदाहरण के लिए, निष्पादित फ़ाइल में सेट किए गए चर बाहर प्रभावित नहीं करते हैं)। संभवतः मिस्टी अतीत से शाब्दिक, जब एक खोल और एक निष्पादन योग्य प्रारूप था। एक निष्पादन योग्य नहीं, यह एक शेल स्क्रिप्ट होना चाहिए।


2
आपने मेरा प्रश्न गलत समझा है। क्या होता है विस्तार से? कम से कम, मुझे यह समझने की ज़रूरत है कि एक शेबंग के लिए क्या जाँच करता है, वह है exec()या शेल? मैं काफी अधिक
जोश
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.