बाश में उपशमन को लागू करने के लिए नियम?


24

मुझे एक उपखंड बनाने के लिए बैश नियम की गलतफहमी प्रतीत होती है। मैंने सोचा था कि कोष्ठक हमेशा एक उपधारा बनाता है, जो अपनी प्रक्रिया के रूप में चलता है।

हालाँकि, ऐसा प्रतीत नहीं होता है। कोड स्निपेट ए (नीचे) में, दूसरा sleepकमांड एक अलग शेल में नहीं चलता है (जैसा कि pstreeदूसरे टर्मिनल में निर्धारित किया गया है)। हालांकि, कोड स्निपेट बी में, दूसरा sleepआदेश है एक अलग खोल में चलाते हैं। स्निपेट्स के बीच एकमात्र अंतर यह है कि दूसरे स्निपेट को कोष्ठकों के भीतर दो कमांड हैं।

जब कोई उपधाराएँ बनाई जाती हैं, तो क्या कोई नियम की व्याख्या कर सकता है?

कोड स्लीपपेट ए:

sleep 5
(
sleep 5
)

कोड स्लीपपेट बी:

sleep 5
(
x=1
sleep 5
)

जवाबों:


20

कोष्ठक हमेशा एक उपधारा शुरू करते हैं। क्या हो रहा है कि बैश का पता चलता है कि sleep 5उस उपधारा द्वारा निष्पादित अंतिम आदेश है, इसलिए यह + के execबजाय कॉल करता है । आदेश में एक ही प्रक्रिया में subshell बदल देता है।forkexecsleep

दूसरे शब्दों में, आधार मामला है:

  1. ( … )एक उपधारा बनाएँ। मूल प्रक्रिया कॉल forkऔर wait। उपप्रकार में, जो एक उपधारा है:
    1. sleepएक बाहरी कमांड है जिसके लिए सबप्रोसेस की जरूरत होती है। सदस्यता कॉल forkऔर wait। निर्वाह में:
      1. उपप्रकार बाह्य कमांड → निष्पादित करता है exec
      2. आखिरकार आदेश समाप्त हो जाता है → exit
    2. wait उपधारा में पूरा होता है।
  2. wait मूल प्रक्रिया में पूरा होता है।

अनुकूलन है:

  1. ( … )एक उपधारा बनाएँ। मूल प्रक्रिया कॉल forkऔर wait। उपप्रकार में, जो कॉल होने तक एक सबमिशन है exec:
    1. sleep एक बाहरी कमांड है, और यह आखिरी चीज है जिसे इस प्रक्रिया को करने की आवश्यकता है।
    2. उपप्रकार बाह्य कमांड → निष्पादित करता है exec
    3. आखिरकार आदेश समाप्त हो जाता है → exit
  2. wait मूल प्रक्रिया में पूरा होता है।

जब आप कॉल करने के बाद कुछ और जोड़ते हैं sleep, तो सबमेल को आसपास रखने की आवश्यकता होती है, इसलिए यह अनुकूलन नहीं हो सकता है।

जब आप कॉल करने से पहले कुछ और जोड़ते हैं sleep, तो अनुकूलन किया जा सकता है (और ksh इसे करता है), लेकिन bash यह नहीं करता (यह इस अनुकूलन के साथ बहुत रूढ़िवादी है)।


कॉलिंग के द्वारा सब्सक्रिप्शन बनाया जाता है forkऔर कॉल करके चाइल्ड प्रोसेस (बाहरी कमांड्स निष्पादित करने के लिए) बनाई जाती हैfork + exec । लेकिन आपके पहले पैरा से पता चलता है कि fork + execसब्सक्रिप्शन के लिए भी कॉल किया जाता है। मैं यहाँ क्या गलत कर रहा हूँ?
हॉक

1
@ झटके fork+ execको उपखंड के लिए नहीं बुलाया जाता है, इसे बाहरी आदेश के लिए कहा जाता है। किसी भी अनुकूलन के बिना, forkउपधारा के लिए एक कॉल है और बाहरी कमांड के लिए एक और एक है। मैंने अपने उत्तर में एक विस्तृत प्रवाह विवरण जोड़ा है।
गिलेस एसओ- बुराई को रोकना '

अपडेट के लिए एक टन धन्यवाद। अब यह बेहतर समझाता है। मैं इससे यह निष्कर्ष निकाल सकता हूं कि (...)(आधार मामले में) मामले में, इस execबात पर निर्भर करने के लिए कॉल नहीं हो सकता है या नहीं कि उप-सदस्य के पास निष्पादित करने के लिए कोई बाहरी आदेश है, जबकि किसी भी बाहरी कमांड को निष्पादित करने के मामले में होना चाहिए fork + exec
haccks

एक और प्रश्न: क्या यह अनुकूलन केवल उप-प्रकार के लिए काम करता है या इसे dateशेल की तरह कमांड के लिए किया जा सकता है ?
हॉक

@ प्रश्न मैं प्रश्न नहीं समझता। यह अनुकूलन एक बाहरी कमांड को लागू करने के बारे में है क्योंकि अंतिम प्रक्रिया एक शेल प्रक्रिया करती है। यह उपधाराओं तक सीमित नहीं है: तुलना करें strace -f -e clone,execve,write bash -c 'date'औरstrace -f -e clone,execve,write bash -c 'date; true'
गाइल्स एसओ- बुराई को रोकें '

4

से उन्नत बैश प्रोग्रामिंग गाइड :

"सामान्य तौर पर, एक स्क्रिप्ट में एक बाहरी कमांड एक उपप्रकार को बंद कर देता है, जबकि एक बैश बिलिन नहीं करता है। इस कारण से, बिल्डरों को अधिक तेज़ी से निष्पादित होता है और अपने बाहरी कमांड समकक्षों की तुलना में कम सिस्टम संसाधनों का उपयोग करता है।"

और थोड़ा और नीचे:

"कोष्ठक के बीच एम्बेडेड एक कमांड सूची एक उपधारा के रूप में चलती है।"

उदाहरण:

[root@talara test]# echo $BASHPID
10792
[root@talara test]# (echo $BASHPID)
4087
[root@talara test]# (echo $BASHPID)
4088
[root@talara test]# (echo $BASHPID)
4089

ओपी कोड का उपयोग करके उदाहरण (छोटी नींद के साथ क्योंकि मैं अधीर हूं):

echo $BASHPID

sleep 2
(
    echo $BASHPID
    sleep 2
    echo $BASHPID
)

उत्पादन:

[root@talara test]# bash sub_bash
6606
6608
6608

2
उत्तर टिम के लिए धन्यवाद। मुझे यकीन नहीं है कि यह पूरी तरह से मेरे सवाल का जवाब देता है। चूंकि "कोष्ठक के बीच एम्बेडेड एक कमांड सूची एक उपखंड के रूप में चलती है", मैं दूसरे sleepसे उप-भाग में चलने की उम्मीद करूंगा (शायद उप-प्रक्रिया के बाद से यह एक अंतर्निहित है, बल्कि उप-भाग के उपप्रकार के बजाय)। हालाँकि, किसी भी मामले में, मुझे उम्मीद है कि एक उपखंड अस्तित्व में होगा, यानी मूल बैश प्रक्रिया के तहत एक बैश उपप्रकार। ऊपर स्निपेट बी के लिए, यह मामला प्रतीत नहीं होता है।
बशफुल

सुधार: क्योंकि sleepयह बिल्ट-इन नहीं लगता है, इसलिए मुझे sleepदोनों स्निपेट में दूसरी कॉल की उम्मीद है कि यह सबहेल्ड प्रक्रिया के उपप्रोसेस में चलेगा।
बशफुल

@ व्यवहारिक मैंने अपने $BASHPIDचर के साथ आपके कोड को हैक करने की स्वतंत्रता ली । दुख की बात यह है कि जिस तरह से आप यह कर रहे थे वह आपको पूरी कहानी नहीं दे रहा था। जवाब में मेरा जोड़ा आउटपुट देखें।
टिम

4

@Gilles जवाब के लिए एक अतिरिक्त नोट।

गिल्स ने कहा: The parentheses always start a subshell.

हालाँकि, ऐसे सब-शेल की संख्या दोहराई जा सकती है:

$ (echo "$BASHPID and $$"; sleep 1)
2033 and 31679
$ (echo "$BASHPID and $$"; sleep 1)
2040 and 31679
$ (echo "$BASHPID and $$"; sleep 1)
2047 and 31679

जैसा कि आप देख सकते हैं, $ $ दोहराता रहता है, और जैसा कि अपेक्षित है, क्योंकि (सही man bashलाइन खोजने के लिए इस कमांड को निष्पादित करें ):

$ LESS=+/'^ *BASHPID' man bash

BashPID
वर्तमान बैश प्रक्रिया की प्रक्रिया आईडी का विस्तार करती है। यह कुछ शर्तों के तहत $ $ से भिन्न होता है, जैसे कि उप-अंशों को जिन्हें फिर से शुरू करने के लिए बैश की आवश्यकता नहीं होती है।

वह है: यदि शेल को पुन: प्रारंभ नहीं किया गया है, तो $ $ समान है।

या इसके साथ:

$ LESS=+/'^ *Special Parameters' man bash

विशेष पैरामीटर
$ शेल की प्रक्रिया आईडी तक फैलता है। एक () उपधारा में, यह वर्तमान शेल की प्रक्रिया आईडी तक फैलता है, उपधारा नहीं।

$$वर्तमान खोल (नहीं subshell) की आईडी है।


1
एक विशिष्ट खंड में बैश मैनपेज खोलने की अच्छी चाल
डैनियल सेरोडियो
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.