मैं कैसे पता लगा सकता / सकती हूँ कि मैं उपश्रेणी में हूँ?


24

मैं exitखुद को टर्मिनल से बाहर निकलने से रोकने के लिए बेसिन की कार्यक्षमता को बदलने के लिए एक फ़ंक्शन लिखने की कोशिश कर रहा हूं ।

मैंने SHLVLपर्यावरण चर का उपयोग करने का प्रयास किया है, लेकिन यह उपधाराओं में नहीं लगता है:

$ echo $SHLVL
1
$ ( echo $SHLVL )
1
$ bash -c 'echo $SHLVL'
2

मेरा कार्य इस प्रकार है:

exit () {
    if [[ $SHLVL -eq 1 ]]; then
        printf '%s\n' "Nice try!" >&2
    else
        command exit
    fi
}

हालांकि यह मुझे exitउप-श्रेणियों के भीतर उपयोग करने की अनुमति नहीं देगा :

$ exit
Nice try!
$ (exit)
Nice try!

यह पता लगाने के लिए एक अच्छी विधि क्या है कि मैं एक उपधारा में हूं या नहीं?



1
ऐसा इसलिए है क्योंकि की है इस । $ SHLVL 1 है क्योंकि आप अभी भी शेल स्तर 1 में हैं, भले ही इको $ SHLVL कमांड "सबस्क्रिप्शन" में चलाया गया हो। उस पद के अनुसार, उपधाराएं कोष्ठक के साथ उत्पन्न होती हैं (...)जो मूल प्रक्रिया के सभी गुणों को प्राप्त करती हैं। प्रदान किए गए उत्तर आपके शेल स्तर का निर्धारण करने के लिए अधिक मजबूत समाधान हैं।
केमोटेप


5
@ मॉसवी मुझे लगता है कि एक अलग सवाल है। उदाहरण के लिए BASH_SUBSHELL(भले ही विवादास्पद) उस प्रश्न पर लागू नहीं होगा।
स्पार्कहॉक

2
HNQ पर शीर्षक देखा और सोचा कि यह एक क्वांटम यांत्रिकी का सवाल है ...
मेहरदाद

जवाबों:


43

बैश में, आप तुलना कर सकते हैं $BASHPIDकरने के लिए$$

$ ( if [ "$$" -eq "$BASHPID" ]; then echo not subshell; else echo subshell; fi )
subshell
$   if [ "$$" -eq "$BASHPID" ]; then echo not subshell; else echo subshell; fi
not subshell

यदि आप $$किसी पार्टीशन में नहीं हैं, तो सब-सब्सक्रिप्शन में समान रहना चाहिए, इसलिए आपको अपनी वास्तविक प्रक्रिया आईडी प्राप्त करने के लिए किसी अन्य तरीके की आवश्यकता होगी।

अपना वास्तविक पिद पाने का एक तरीका है sh -c 'echo $PPID'। यदि आप ( … )इसे एक सादे मैदान में रखते हैं तो यह काम नहीं कर सकता है, क्योंकि आपके खोल ने कांटा दूर कर दिया है। ( : ; sh -c 'echo $PPID'; : )यह सुनिश्चित करने के लिए अतिरिक्त नो-ऑप कमांडों को आज़माएं कि उप-भाग बहुत अधिक जटिल है ताकि वह अनुकूलित हो सके। उस दृष्टिकोण के लिए स्टैक ओवरफ्लो पर क्रेडिट जॉन 1024 पर जाता है ।


आप शायद इसे बदलना चाहते हैं  (sh -c 'echo $PPID'; : )- John1024 के उत्तर पर मेरी टिप्पणी देखें ।
जी-मैन का कहना है कि 'मोनिका' की बहाली

@ जी-मैन वेल, यह सिर्फ इसका परीक्षण करने के लिए था (चूंकि वास्तविक उपयोग में यह किसी तरह से अधिक जटिल होगा) ... लेकिन हाँ, सबसे अच्छा होगा यदि परीक्षण सभी गोले में काम करता है। इसलिए मैंने पहले और बाद में दोनों जगह नो-ऑप लगाया है, जो उम्मीद है कि सब कुछ संभाल लेगा।
19:45

38

कैसे के बारे में BASH_SUBSHELL?


      जब उस वातावरण में शेल
      निष्पादित होना शुरू हो जाता है तो BASH_SUBSHELL एक-एक सबस्क्रिप्शन या सबस्क्रिप्शन वातावरण में बढ़ जाता है। प्रारंभिक मान 0 है।

$ echo $BASH_SUBSHELL
0
$ (echo $BASH_SUBSHELL)
1

16
फिल्म इंसेप्शन में यह एक सुविधाजनक कमांड होता।
एरिक डुमिनील

शुरुआत में यह शायद $ SHLVL है
दादी

19

[यह एक टिप्पणी होनी चाहिए थी, लेकिन मेरी टिप्पणी मध्यस्थों द्वारा हटा दी जाती है, इसलिए यह एक उत्तर के रूप में रहेगा कि मैं इसे हटाए जाने पर भी संदर्भ के रूप में उपयोग कर सकता हूं]

का उपयोग करना BASH_SUBSHELLपूरी तरह से अविश्वसनीय है क्योंकि यह केवल कुछ उपधाराओं में 1 पर सेट होता है , सभी उपधाराओं में नहीं।

$ (echo $BASH_SUBSHELL)
1
$ echo $BASH_SUBSHELL | cat
0

यह दावा करने से पहले कि सबप्रोसेस एक पाइपलाइन कमांड में चलाया जाता है , वास्तव में वास्तविक उपसमूह नहीं है, इस man bashस्निपेट पर विचार करें :

एक पाइप लाइन में प्रत्येक कमांड को एक अलग प्रक्रिया के रूप में निष्पादित किया जाता है (यानी, एक सबहेल में)।

और व्यावहारिक निहितार्थ - यह है कि क्या एक स्क्रिप्ट टुकड़ा एक उपप्रकार चलाया जाता है या नहीं, जो आवश्यक है, कुछ शब्दावली नहीं।

एकमात्र समाधान, जैसा कि पहले से ही इस प्रश्न के उत्तर में बताया गया है कि यह जाँचना है कि क्या $BASHPIDबराबरी $$या, कम या ज्यादा कुशल है:

if [ "$(exec sh -c 'echo "$PPID"')" != "$$" ]; then
    echo you\'re in a subshell
fi

11
Nit: BASH_SUBSHELLबहुत मज़बूती से सेट किया गया है, लेकिन इसके मूल्य को सही ढंग से प्राप्त करना iffy है। ध्यान दें कि डॉक्स क्या कहता है: " शेल में उस वातावरण में निष्पादन शुरू होने पर प्रत्येक सबस्क्रिप्शन या सबस्क्रिप्शन वातावरण में एक से बढ़े हुए हैं। " मुझे लगता है कि पाइप उदाहरण में, बैश अभी तक उस सब-सील्ड में निष्पादित नहीं किया गया है जब चर का विस्तार होता है। आप तुलना कर सकते हैं echo $BASH_VERSIONके साथ declare -p BASH_VERSION- उत्तरार्द्ध चाहिए मज़बूती से पाइप, पृष्ठभूमि नौकरियों, आदि के साथ उत्पादन 1
muru

6
यहां तक ​​कि, eval 'echo $BASH_SUBSHELL $BASHPID' | cat1 के लिए आउटपुट देगा BASH_SUBSHELL, क्योंकि निष्पादन शुरू होने के बाद चर का विस्तार किया जाता है।
मुरु

4
उन सभी तर्कों को भी प्रतिस्थापन, बीजी प्रक्रियाओं को प्रोसेस और कमांड करने के लिए आवेदन करना चाहिए, फिर भी यह केवल पाइपलाइन हैं जो अलग हैं। कोड को देखते हुए, अग्रगामी subshell_levelवास्तव में अग्रभूमि पाइपलाइनों के मामले में आस्थगित किया जाता है , जो संभवतः कुछ कारण है, लेकिन जो मैं बाहर करने में सक्षम नहीं हूं; ;-)
mosvy

2
आप सही हे। लगता है कि चेत ने स्पष्ट रूप से इसे इस तरह इरादा किया है। lists.gnu.org/archive/html/bug-bash/2015-06/msg00050.html : "BASH_SUBSHELL उपाय (...) उपधारा, पाइपलाइन तत्व नहीं।" lists.gnu.org/archive/html/bug-bash/2015-06/msg00054.html : "मैं इस बारे में सोचने जा रहा हूं कि क्या मुझे यथास्थिति का दस्तावेजीकरण करना चाहिए या 'सब-सब्सक्रिप्शन' की परिभाषा का विस्तार करना चाहिए जो $ BASH_SUZHELL दर्शाता है। "
मुरु

2
@JoL आप गलत हैं, विस्तार अलग प्रक्रिया में भी होता है, कृपया इस चर्चा से लिंक और उदाहरण पढ़ें; या बस के साथ प्रयास करें echo $$ $BASHPID $BASH_SUBSHELL | cat
मच्छी
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.