Bashrc यह क्यों जाँचता है कि क्या वर्तमान शेल संवादात्मक है?


62

मेरे आर्क पर स्थापित करें, /etc/bash.bashrcऔर /etc/skel/.bashrcइन पंक्तियों को शामिल करें:

# If not running interactively, don't do anything
[[ $- != *i* ]] && return

डेबियन पर, /etc/bash.bashrcहै:

# If not running interactively, don't do anything
[ -z "$PS1" ] && return

और /etc/skel/.bashrc:

# If not running interactively, don't do anything
case $- in
    *i*) ;;
      *) return;;
esac

के अनुसार man bash, हालांकि, गैर-सहभागी गोले यहां तक कि इन फ़ाइलों को पढ़ने नहीं है:

   When  bash  is  started  non-interactively,  to run a shell script, for
   example, it looks for the variable BASH_ENV in the environment, expands
   its  value if it appears there, and uses the expanded value as the name
   of a file to read and execute.  Bash behaves as if the  following  com
   mand were executed:
          if [ -n "$BASH_ENV" ]; then . "$BASH_ENV"; fi
   but  the value of the PATH variable is not used to search for the file
   name.

अगर मैं सही तरीके से समझूं, तो *.bashrcफाइलों को केवल तभी पढ़ा जाएगा जब BASH_ENVउन्हें इंगित करना है। यह कुछ ऐसा है जो संयोग से नहीं हो सकता है और केवल तब होगा जब किसी ने स्पष्ट रूप से तदनुसार चर सेट किया हो।

ऐसा लगता है कि स्क्रिप्ट के स्रोत को उपयोगकर्ता .bashrcद्वारा स्वचालित रूप से सेट करने BASH_ENVसे कुछ होने की संभावना टूट जाती है , जो कुछ काम आ सकता है। यह देखते हुए कि गैर-अंतःक्रियात्मक रूप से चलने पर बैश इन फ़ाइलों को कभी नहीं पढ़ेगा जब तक कि स्पष्ट रूप से ऐसा करने के लिए नहीं कहा जाता है, तो डिफ़ॉल्ट *bashrcफाइलें इसे क्यों नहीं रोकती हैं?


5
व्यावहारिक उत्तर के लिए, देखें एससीपी बिना त्रुटि के विफल हो जाता है
गाइल्स

जवाबों:


69

यह एक सवाल है कि मैं कुछ हफ्ते पहले यहां पोस्ट करने जा रहा था। टेराडॉन की तरह , मुझे समझ में आया कि .bashrcयह केवल इंटरैक्टिव बैश शेल के लिए खट्टा है , इसलिए .bashrcयह जांचने की कोई आवश्यकता नहीं होनी चाहिए कि क्या यह एक इंटरैक्टिव शेल में चल रहा है। भ्रामक रूप से, मेरे द्वारा उपयोग किए जाने वाले सभी वितरण (उबंटू, आरएचईएल और साइगविन) में कुछ प्रकार की जांच (परीक्षण $-या $PS1) थी ताकि यह सुनिश्चित किया जा सके कि वर्तमान शेल संवादात्मक है। मुझे कार्गो पंथ प्रोग्रामिंग पसंद नहीं है, इसलिए मैंने इस कोड के उद्देश्य को अपने में समझने के लिए निर्धारित किया है .bashrc

बैश में दूरदराज के गोले के लिए एक विशेष मामला है

इस मुद्दे पर शोध करने के बाद, मुझे पता चला कि दूरस्थ गोले को अलग तरह से व्यवहार किया जाता है। जबकि गैर-इंटरएक्टिव बैश शेल सामान्य रूप ~/.bashrcसे स्टार्ट-अप पर कमांड नहीं चलाते हैं , जब शेल को रिमोट शेल द्वारा आमंत्रित किया जाता है, तो एक विशेष मामला बनाया जाता है :

बैश यह निर्धारित करने का प्रयास करता है कि यह कब नेटवर्क कनेक्शन से जुड़े अपने मानक इनपुट के साथ चलाया जा रहा है, जब दूरस्थ शेल डेमॉन द्वारा निष्पादित किया जाता है, आमतौर पर rshd, या सुरक्षित शेल डेमॉन sshd। यदि बैश यह निर्धारित करता है कि यह इस तरह से चलाया जा रहा है, तो यह ~ / .bashrc से कमांड पढ़ता है और निष्पादित करता है, यदि वह फाइल मौजूद है और पढ़ने योग्य है। यदि ऐसा किया जाता है तो यह ऐसा नहीं करेगा sh--norcविकल्प इस व्यवहार को बाधित करने के लिए इस्तेमाल किया जा सकता है, और --rcfileविकल्प अन्य फ़ाइल पढ़ने के लिए मजबूर करने के लिए इस्तेमाल किया जा सकता, लेकिन न तो rshdहै और न ही sshdआम तौर पर उन विकल्पों के साथ खोल आह्वान या उन्हें निर्दिष्ट करने की अनुमति देते हैं।

उदाहरण

रिमोट की शुरुआत में निम्नलिखित डालें .bashrc। (यदि परीक्षण के दौरान इसे अस्थायी रूप से अक्षम कर दिया .bashrcजाता है .profileया .bash_profile:

echo bashrc
fun()
{
    echo functions work
}

स्थानीय रूप से निम्न आदेश चलाएँ:

$ ssh remote_host 'echo $- $0'
bashrc
hBc bash
  • कोई iमें $-इंगित करता है कि खोल है गैर-सहभागी
  • कोई अग्रणी -में $0इंगित करता है कि खोल एक है लॉगिन खोल

रिमोट में परिभाषित शेल फ़ंक्शन .bashrcभी चलाए जा सकते हैं:

$ ssh remote_host fun
bashrc
functions work

मैंने देखा है कि ~/.bashrcहै केवल जब एक आदेश के लिए तर्क के रूप में निर्दिष्ट किया जाता है sourced ssh। यह समझ में आता है: जब sshएक नियमित लॉगिन खोल शुरू करने के लिए उपयोग किया जाता है, .profileया .bash_profileचलाया जाता है (और .bashrcकेवल इन फ़ाइलों में से एक द्वारा स्पष्ट रूप से किए जाने पर खट्टा हो जाता है)।

मुख्य .bashrc(गैर-संवादात्मक) रिमोट कमांड चलाने के दौरान मुख्य लाभ यह हो सकता है कि शेल फ़ंक्शन चलाए जा सकते हैं। हालांकि, एक ठेठ में अधिकांश कमांड .bashrcकेवल एक इंटरैक्टिव शेल में प्रासंगिक होते हैं, उदाहरण के लिए, एलियास का विस्तार नहीं किया जाता है जब तक कि शेल इंटरैक्टिव नहीं होता है।

दूरस्थ फ़ाइल स्थानांतरण विफल हो सकता है

यह जब एक समस्या आमतौर पर नहीं है rshया sshएक इंटरैक्टिव लॉगिन खोल या जब गैर-सहभागी गोले आदेशों को चलाने के लिए किया जाता है शुरू करने के लिए उपयोग किया जाता है। हालाँकि, यह प्रोग्राम के लिए एक समस्या हो सकती हैrcp , जैसे कि scpऔर डेटा ट्रांसफर करने के लिए रिमोट शेल काsftp उपयोग करें ।

यह पता चलता है कि रिमोट उपयोगकर्ता का डिफ़ॉल्ट शेल (जैसे बाश) scpकमांड का उपयोग करते समय अंतर्निहित है । मैन पेज में इसका कोई उल्लेख नहीं है - केवल एक उल्लेख है जो इसके डेटा ट्रांसफर के लिए scpउपयोग करता है ssh। इसका परिणाम यह होता है कि यदि .bashrcमानक आउटपुट पर प्रिंट करने वाली कोई भी कमांड होती है, तो फ़ाइल स्थानांतरण विफल हो जाएगा , उदाहरण के लिए, त्रुटि के बिना scp विफल

15 साल पहले की इस संबंधित Red Hat बग रिपोर्ट को भी देखें, जब / / etc / bashrc (जो अंततः के रूप में बंद हो गया था WONTFIX) में एक इको कमांड है तो scp टूट जाता है

क्यों scpऔर sftpअसफल

एससीपी (सिक्योर कॉपी) और एसएफटीपी (सिक्योर फाइल ट्रांसफर प्रोटोकॉल) स्थानीय और दूरस्थ छोरों के लिए फाइल (एस) हस्तांतरित होने के बारे में जानकारी का आदान-प्रदान करने के लिए अपने स्वयं के प्रोटोकॉल हैं। दूरस्थ छोर से कोई भी अनपेक्षित पाठ प्रोटोकॉल के हिस्से के रूप में (गलत तरीके से) व्याख्या किया गया है और हस्तांतरण विफल रहता है। घोंघा किताब से एक FAQ के अनुसार

क्या अक्सर ऐसा होता है, हालांकि, वहाँ सर्वर पर या तो सिस्टम में बयान या प्रति-उपयोगकर्ता खोल स्टार्टअप फ़ाइलें (हैं कि .bashrc, .profile, /etc/csh.cshrc, .login, आदि) जो प्रवेश पर उत्पादन पाठ संदेश, इरादा तरह मनुष्य के द्वारा पढ़ा जा करने के लिए ( fortune, echo "Hi there!", आदि।)।

इस तरह के कोड को केवल इंटरेक्टिव लॉगिन पर आउटपुट का उत्पादन करना चाहिए, जब ttyमानक इनपुट से जुड़ा होता है। यदि यह इस परीक्षण को नहीं करता है, तो यह इन पाठ संदेशों को सम्मिलित करेगा जहां वे नहीं हैं: इस मामले में scp2/ sftpऔर के बीच प्रोटोकॉल स्ट्रीम को प्रदूषित कर रहा है sftp-server

शेल स्टार्टअप फाइलें बिल्कुल प्रासंगिक हैं, इसका कारण यह है कि sshd उपयोगकर्ता की ओर से किसी भी कार्यक्रम को शुरू करते समय उपयोगकर्ता के शेल को नियोजित किया जाता है (उदाहरण के लिए / बिन / sh -c "कमांड")। यह एक यूनिक्स परंपरा है, और इसके फायदे हैं:

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

एससीपी प्रोटोकॉल विवरण

एससीपी कैसे काम करता है, इसके विवरण में रुचि रखने वालों के लिए, मुझे दिलचस्प जानकारी मिली कि एससीपी प्रोटोकॉल कैसे काम करता है, जिसमें दूरस्थ पक्ष पर बातूनी खोल प्रोफाइल के साथ रनिंग एसपीपी पर विवरण शामिल हैं ? :

उदाहरण के लिए, यह हो सकता है यदि आप इसे दूरस्थ सिस्टम पर अपने शेल प्रोफाइल में जोड़ते हैं:

गूंज ""

यह सिर्फ लटका क्यों है? इस तरह से आता है कैसे scpमें स्रोत मोड पहले प्रोटोकॉल संदेश की पुष्टि के लिए इंतजार कर रहा है। यदि यह द्विआधारी 0 नहीं है, तो यह उम्मीद करता है कि यह एक दूरस्थ समस्या की सूचना है और नई लाइन आने तक त्रुटि संदेश बनाने के लिए अधिक वर्णों की प्रतीक्षा करता है। चूंकि आपने पहले एक के बाद एक और नई लाइन नहीं छापी थी, इसलिए आपका स्थानीय scpबस लूप में बंद रहता है read(2)। इस बीच, रिमोट प्रोफाइल पर शेल प्रोफाइल संसाधित होने के बाद, scpसिंक मोड शुरू किया गया था, जो कि ब्लॉक भी करता है read(2), डेटा ट्रांसफर की शुरुआत को दर्शाते हुए एक बाइनरी शून्य की प्रतीक्षा करता है।

निष्कर्ष / TLDR

एक ठेठ में अधिकांश बयान .bashrcकेवल एक इंटरैक्टिव शेल के लिए उपयोगी होते हैं - जब दूरस्थ कमांड के साथ rshया नहीं चल रहा हो ssh। ऐसी अधिकांश स्थितियों में, शेल चरों, उपनामों और परिभाषित कार्यों की स्थापना वांछित नहीं है - और किसी भी पाठ को मानक रूप से प्रिंट करना सक्रिय रूप से हानिकारक है यदि प्रोग्राम जैसे scpया का उपयोग करके फ़ाइलों को स्थानांतरित करना sftp। मौजूदा शेल गैर-इंटरैक्टिव होने की पुष्टि करने के बाद बाहर निकलना सबसे सुरक्षित व्यवहार है .bashrc


अच्छा लेख। लेकिन मुझे उसके साथ क्या करना चाहिए? मेरे पास .bashrc में चेक है लेकिन फिर भी 0 कोड के साथ बाहर निकलें और रिमोट बॉक्स में कुछ भी कॉपी न करें
ses

@ses एक नया प्रश्न पूछना सबसे अच्छा होगा जहाँ आप अपनी स्थिति का अधिक विस्तार से वर्णन कर सकते हैं।
एंथनी गोगेगन

16

मैन पेज का उल्लेख करने के लिए उपेक्षा करता है कि गैर-संवादात्मक दूरस्थ गोले के bashस्रोत भी .bashrc, जैसे कि

ssh hostname command

http://git.savannah.gnu.org/cgit/bash.git/tree/shell.c#n1010

 COMMAND        EXECUTE BASHRC
 --------------------------------
 bash -c foo        NO
 bash foo           NO
 foo                NO
 rsh machine ls     YES (for rsh, which calls 'bash -c')
 rsh machine foo    YES (for shell started by rsh) NO (for foo!)
 echo ls | bash     NO
 login              NO
 bash               YES

http://git.savannah.gnu.org/cgit/bash.git/tree/shell.c#n1050

          /* If we were run by sshd or we think we were run by rshd, execute
             ~/.bashrc if we are a top-level shell. */
          if ((run_by_ssh || isnetconn (fileno (stdin))) && shell_level < 2)
            {
              maybe_execute_file (SYS_BASHRC, 1);
              maybe_execute_file (bashrc_file, 1);

क्या आप अपने .bash_profile (या .profile) से अपने .bashrc स्रोत करते हैं?
ग्लेन जैकमैन

हां, लेकिन वह बात नहीं है। एक खाली एक .bash_profileही व्यवहार प्रदर्शित करेगा।
मिकेल

यकीन नहीं हो रहा है कि मुझे क्या दिखा रहा है। क्या आप ऐसा कह रहे हैं rsh(जो मैंने कभी उपयोग नहीं किया है) स्रोत ~/.bashrc? और विस्तार से, लिनक्स डिस्ट्रोस इसे bashकेवल उस स्थिति में ब्लॉक कर देता है जब कोई स्क्रिप्ट के साथ चलने की कोशिश करता है rsh? ssh serverस्पर्श नहीं करना चाहिए .bashrcक्योंकि यह वैसे भी एक लॉगिन शेल है। तब तक नहीं जब तक कि आपका सिस्टम उन स्रोतों में से एक नहीं है, जो कि ~ / .bashrc` से हैं ~/.profile। और ऐसा ssh server commandकरना भी नहीं चाहिए। निश्चित रूप से मेरे सिस्टम पर नहीं है।
terdon

2
नहीं। मैंने आपको bashस्रोत से जोड़ा है, स्रोत से नहीं rsh। :) टिप्पणी पर भी लागू होता है ssh, यह बहुत पहले लिखा गया था। अधिक स्रोत के साथ अद्यतन उत्तर देखें।
मिकेल

आह, यह उपयोगी है, धन्यवाद। हालांकि मैं इसका परीक्षण कैसे करूंगा? मैं एक जोड़ने की कोशिश की echoपर सबसे ऊपर /etc/bash.bashrcऔर ~/.bashrc(इंटरैक्टिव खोल परीक्षण से पहले) और फिर साथ लक्ष्य मशीन में ssh ssh server hostnameऔर जब तक hostnameचलाया गया था, मैं अपने गूँज में से किसी को नहीं देखा। क्या यह है कि मेरी shell_level(जो कुछ भी है) नहीं है <2?
terdon

5

कन्वेंशन द्वारा, .bashrcवह स्थान है जहां उपयोगकर्ता शेल के लिए अनुकूलित कॉन्फ़िगरेशन को संग्रहीत करता है।

ये अनुकूलित कॉन्फ़िगरेशन पर्यावरण चर, उपनाम, फैंसी प्रॉम्प्ट हो सकते हैं। एक गैर-इंटरैक्टिव शेल के साथ, उन चीजों की कमी अर्थहीन है। इसके अलावा, एक गैर-इंटरैक्टिव शेल कई संदर्भों में कॉल किया जा सकता है, आपको यकीन नहीं है कि उन पर्यावरण चर झूठे नकारात्मक मामले, या यहां तक ​​कि सुरक्षा की चपेट में आ सकते हैं।

निकटतम उदाहरण एक उपनाम है जैसे:

alias cp='cp -i'

फिर यह आपके गैर-इंटरैक्टिव शेल को हमेशा के लिए लटका देता है।

तो यह .bashrcसुनिश्चित करने के लिए कि हमें परेशानी नहीं होगी , चेक सबसे ऊपर है ।


क्योंकि शेल को गैर-संवादात्मक लॉगिन शेल कहा जा सकता है , इसलिए स्पष्ट रूप से ब्लॉक सोर्सिंग का *bashrcकोई मतलब नहीं है।

जब खोल रहा था गैर-सहभागी लॉगिन शेल के रूप में कहा जाता है , यह स्रोत /etc/profileहै, तो स्रोत पहले एक में पाया ~/.bash_profile, ~/.bash_loginऔर ~/.profile:

जब बैश को एक इंटरेक्टिव लॉगिन शेल के रूप में या एक गैर-इंटरेक्टिव शेल के रूप में - एल्गिन विकल्प के रूप में लागू किया जाता है , तो यह पहले फ़ाइल / आदि / प्रोफाइल से कमांड को पढ़ता है और निष्पादित करता है, यदि वह फ़ाइल मौजूद है। उस फ़ाइल को पढ़ने के बाद, यह उस क्रम में ~ / .bash_profile, ~ / .bash_login और ~ / .profile की तलाश करता है, और पहले मौजूद से कमांड पढ़ता और निष्पादित करता है और पढ़ने योग्य होता है।

कुछ भी नहीं उन फ़ाइलों को सोर्स करने से रोकते हैं .bashrc, इसलिए अंदर चेक .bashrcकरना सुरक्षित है और चीजों को सरल बनाते हैं।


हाँ मुझे पता है। यही कारण है कि गैर-संवादात्मक गोले *bashrcफाइलों को स्रोत नहीं बनाते हैं । मेरा सवाल यह है कि विभिन्न लिनक्स विक्रेता इन फ़ाइलों को पढ़ने से स्पष्ट रूप से गैर-संवादात्मक गोले को रोकने की परेशानी में जाते हैं यदि इन फ़ाइलों को वैसे भी गैर-संवादात्मक गोले द्वारा नहीं पढ़ा जाता है।
terdon

1
@terdon: क्योंकि शेल को गैर-संवादात्मक लॉगिन शेल कहा जा सकता है , फिर एक लॉगिन शेल स्रोत होगा .bash_profile, जो स्रोत हो सकता है .bashrc
cuonglm

नहीं, गैर-संवादात्मक गोले में, केवल एक चीज जो पढ़ी जाती है $BASH_ENV। दोनों *profileऔर *bashrcध्यान नहीं दिया जाता। या, कम से कम, कि आदमी पृष्ठ क्या कहता है। हालाँकि, जैसा कि मिकेल ने दिखाया है कि आदमी पेज झूठ बोल रहा होगा।
terdon

@terdon: इसमें लिंक के साथ मेरा अद्यतन उत्तर पढ़ें। क्या आपने bash -l -c :एक गैर-संवादात्मक लॉगिन शेल को लागू करने का प्रयास किया है?
क्यूंग्लम

वाह। आप बिल्कुल सही कह रहे है। मैंने उस हिस्से को लगभग --login100 बार पढ़ा है लेकिन, जाहिर है, यह कभी पंजीकृत नहीं हुआ था। धन्यवाद!
terdon
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.