2008-12-09 21 views
6

प्रश्न के बारे में सवाल:/usr/bin/env कुटिया लाइन pecularities

  • क्या गिरी है करता है अगर आप कुटिया लाइन में एक खोल स्क्रिप्ट छड़ी?
  • कर्नेल कैसे पता चलता है कि कौन सा दुभाषिया लॉन्च करना है?

स्पष्टीकरण:

मैं हाल ही में चारों ओर /usr/bin/env एक आवरण लिखने के लिए क्योंकि मेरी सीजीआई पर्यावरण मुझे विश्व स्तर पर छोड़कर, पथ चर सेट करने की अनुमति नहीं (चाहता था जो निश्चित रूप से बेकार है!)।

तो मैंने सोचा, "ठीक है, चलो प्रीपेन्पाट सेट करें और पाथ एनवी के चारों ओर एक रैपर में सेट करें।" जिसके परिणामस्वरूप लिपि (यहाँ env.1 कहा जाता है) इस तरह देखा:

#!/bin/bash 
/usr/bin/env PATH=$PREPENDPATH:$PATH $* 

जो लगता है कि यह काम करना चाहिए। मैं जाँच की वे दोनों कैसे प्रतिक्रिया करते हैं, PREPENDPATH सेट करने के बाद:

$ which /usr/bin/env python 
/usr/bin/env 
/usr/bin/python 

$ which /usr/bin/env.1 python 
/usr/bin/env 
/home/pi/prepend/bin/python 

बिल्कुल देखो सही! अब तक सब ठीक है. लेकिन देखो "हैलो वर्ल्ड!" के साथ क्या होता है।

# Shebang is #!/usr/bin/env python 
$ test-env.py 
Hello World! 

# Shebang is #!/usr/bin/env.1 python 
$ test-env.1.py 
Warning: unknown mime-type for "Hello World!" -- using "application/*" 
Error: no such file "Hello World!" 

मुझे लगता है कि मुझे यूनिक्स के बारे में कुछ मौलिक याद आ रही है।

मैं मूल env के स्रोत कोड को देखने के बाद भी बहुत खो गया हूं। यह पर्यावरण सेट करता है और कार्यक्रम लॉन्च करता है (या ऐसा लगता है कि मुझे ...)।

उत्तर

6

सबसे पहले, आपको शायद ही कभी $* का उपयोग करना चाहिए और आपको लगभग हमेशा "[email protected]" का उपयोग करना चाहिए। एसओ पर यहां कई प्रश्न हैं जो इनके इन्स और आउट को समझाते हैं।

दूसरा - env कमांड में दो मुख्य उपयोग हैं। एक मौजूदा पर्यावरण को मुद्रित करना है; दूसरा इसे चलाने के दौरान कमांड के पर्यावरण को पूरी तरह से नियंत्रित करना है। तीसरा उपयोग, जिसे आप प्रदर्शित कर रहे हैं, पर्यावरण को संशोधित करना है, लेकिन स्पष्ट रूप से इसके लिए कोई आवश्यकता नहीं है - गोले आपके लिए इसे संभालने में काफी सक्षम हैं।

मोड 1:

env 

मोड 2:

env -i HOME=$HOME PATH=$PREPENDPATH:$PATH ... command args 

इस संस्करण में सभी विरासत में मिला वातावरण चर को रद्द करता है और ठीक पर्यावरण ENVVAR = मूल्य विकल्प द्वारा निर्धारित साथ command चलाता है।

तीसरा मोड - पर्यावरण में संशोधन - कम महत्वपूर्ण है क्योंकि आप नियमित (सभ्य) गोले के साथ यह ठीक कर सकते हैं। उदाहरण के लिए - (। इसका मतलब है कि "नहीं सी खोल" फिर से, वहाँ अन्य समझा है कि कि जवाब के साथ इतने पर सवाल कर रहे हैं), तो आप पूरी तरह से अच्छी तरह से कर सकता है:

#!/bin/bash 
export PATH=${PREPENDPATH:?}:$PATH 
exec python "[email protected]" 

यह कहना है कि $PREPENDPATH एक गैर करने के लिए सेट कर दिया जाता पर्यावरण में खाली स्ट्रिंग, और उसके बाद इसे $PATH पर प्रस्तुत करता है, और नई पैथ सेटिंग निर्यात करता है। फिर, उस नए पथ का उपयोग करके, यह प्रासंगिक तर्कों के साथ python प्रोग्राम निष्पादित करता है। exec शेल स्क्रिप्ट को python के साथ बदल देता है। ध्यान दें कि यह काफी अलग है:

#!/bin/bash 
PATH=${PREPENDPATH:?}:$PATH exec python "[email protected]" 

सतही रूप से, यह वही है। हालांकि, यह प्रक्रिया के पर्यावरण में पीएटीएच के नए मूल्य के बावजूद, पूर्व-मौजूदा पीएटीएच पर पाए गए python निष्पादित करेगा। तो, उदाहरण में, आप /usr/bin से पाइथन निष्पादित करना समाप्त कर देंगे और /home/pi/prepend/bin से नहीं।

आपकी स्थिति में, शायद मैं env का उपयोग नहीं करता और स्पष्ट निर्यात के साथ स्क्रिप्ट का उपयुक्त संस्करण उपयोग करता हूं।

env कमांड असामान्य है क्योंकि यह शेष आदेश से विकल्पों को अलग करने के लिए डबल-डैश को नहीं पहचानता है। यह कुछ हद तक नहीं है क्योंकि इसमें कई विकल्प नहीं हैं, और कुछ हद तक यह स्पष्ट नहीं है कि ENVVAR = मान विकल्प डबल डैश से पहले या उसके बाद आते हैं या नहीं।

मेरे पास वास्तव में डेटाबेस सर्वर के विभिन्न संस्करणों (चलाने के लिए) की एक श्रृंखला है। इन लिपियों वास्तव में env (और देसी कार्यक्रमों का समूह) का उपयोग सर्वर वातावरण को नियंत्रित करने के:

#!/bin/ksh 
# 
# @(#)$Id: boot.black_19.sh,v 1.3 2008/06/25 15:44:44 jleffler Exp $ 
# 
# Boot server black_19 - IDS 11.50.FC1 

IXD=/usr/informix/11.50.FC1 
IXS=black_19 
cd $IXD || exit 1 

IXF=$IXD/do.not.start.$IXS 
if [ -f $IXF ] 
then 
    echo "$0: will not start server $IXS because file $IXF exists" 1>&2 
    exit 1 
fi 

ONINIT=$IXD/bin/oninit.$IXS 
if [ ! -f $ONINIT ] 
then ONINIT=$IXD/bin/oninit 
fi 

tmpdir=$IXD/tmp 
DAEMONIZE=/work1/jleffler/bin/daemonize 
stdout=$tmpdir/$IXS.stdout 
stderr=$tmpdir/$IXS.stderr 

if [ ! -d $tmpdir ] 
then asroot -u informix -g informix -C -- mkdir -p $tmpdir 
fi 

# Specialized programs carried to extremes: 
# * asroot sets UID and GID values and then executes 
# * env, which sets the environment precisely and then executes 
# * daemonize, which makes the process into a daemon and then executes 
# * oninit, which is what we really wanted to run in the first place! 
# NB: daemonize defaults stdin to /dev/null and could set umask but 
#  oninit dinks with it all the time so there is no real point. 
# NB: daemonize should not be necessary, but oninit doesn't close its 
#  controlling terminal and therefore causes cron-jobs that restart 
#  it to hang, and interactive shells that started it to hang, and 
#  tracing programs. 
# ??? Anyone want to integrate truss into this sequence? 

asroot -u informix -g informix -C -a dbaao -a dbsso -- \ 
    env -i HOME=$IXD \ 
     INFORMIXDIR=$IXD \ 
     INFORMIXSERVER=$IXS \ 
     INFORMIXCONCSMCFG=$IXD/etc/concsm.$IXS \ 
     IFX_LISTEN_TIMEOUT=3 \ 
     ONCONFIG=onconfig.$IXS \ 
     PATH=/usr/bin:$IXD/bin \ 
     SHELL=/usr/bin/ksh \ 
     TZ=UTC0 \ 
    $DAEMONIZE -act -d $IXD -o $stdout -e $stderr -- \ 
    $ONINIT "[email protected]" 

case "$*" in 
(*v*) track-oninit-v $stdout;; 
esac 
+0

यह उपयोगी जानकारी है, लेकिन जैसा कि ओ पी कहते हैं, उसका/उसकी गिरी गैर नहीं चलेंगे एक शेबांग लाइन के पहले तत्व के रूप में द्विआधारी (जैसे कि आप प्रदान करते हुए बैश स्टब्स)। मेरा या तो नहीं होगा; विशेष रूप से, कर्नेल चुपचाप वांछित (गैर-बाइनरी) दुभाषिया में समस्याग्रस्त शेबांग लाइन के साथ स्क्रिप्ट चलाने में विफल रहता है, और फिर मेरा खोल इसके बजाय स्क्रिप्ट चलाने की कोशिश करेगा। (मेरी समझ यह है कि यह एक पुराना समय का शैल व्यवहार है जो कई गोले बनाए रखता है।) – dubiousjim

+0

मुझे समझ में नहीं आता कि आप क्या कह रहे हैं? क्या आप दावा कर रहे हैं कि अभी भी (अभी भी) गोले या कर्नेल हैं जो स्क्रिप्ट की पहली पंक्ति के रूप में '#!/Bin/bash' या' #!/Bin/ksh' को संभाल नहीं पाएंगे? मैं दावा नहीं कर रहा हूं या दिखा रहा हूं कि आप शेबांग के रूप में '#!/कुछ/स्क्रिप्ट 'का उपयोग कर सकते हैं। –

+0

पहले दावा नहीं कर रहा है। ओपी का सवाल दूसरे के बारे में है, हालांकि: उसने पूछा, "यदि आप शेबांग लाइन में शेल-स्क्रिप्ट चिपकते हैं तो कर्नेल क्या करता है?" और उसके बाद समस्याएं रिपोर्ट करती हैं जो env.1 को शेबांग लाइन के रूप में उपयोग करने से आती हैं, जहां env.1 एक स्क्रिप्ट है। (जैसा भी होता है, यह शेबैंग लाइनों के बारे में सीमाओं की चर्चाओं की खोज कर रहा था जो मुझे यहां लाए। और मुझे पता चला कि आपकी पोस्ट में उपयोगी जानकारी थी, इसलिए इसका योगदान करने के लिए धन्यवाद। मैं बस अन्य पाठकों के लिए बता रहा था, जो बाद में आ सकते हैं, जो आप चर्चा करते हैं वह ओपी के खिलाफ आने वाली सीमा को दूर करने में मदद नहीं करता है।) – dubiousjim

4

आपको shebang के बारे में विकिपीडिया लेख सावधानीपूर्वक पढ़ना चाहिए।

जब आपका सिस्टम शेबैंग से संबंधित जादू संख्या को देखता है, तो यह शेबैंग के बाद दिए गए पथ पर execve करता है और स्क्रिप्ट को स्वयं तर्क के रूप में देता है।

आपकी स्क्रिप्ट विफल रहता है क्योंकि फ़ाइल आप दे (/usr/bin/env.1) एक निष्पादन नहीं है, लेकिन एक कुटिया से ही शुरू होता है ....

आदर्श रूप में, आप इसे का उपयोग कर हल कर सकता है ...

#!/usr/bin/env /usr/bin/env.1 python 

यह लिनक्स पर हालांकि काम नहीं करेगा के रूप में यह व्यवहार करता है "/usr/bin/env.1 python" एक मार्ग के रूप में (यह तर्क विभाजित नहीं करता है)

तो केवल: एक कुटिया के रूप में इस लाइन के साथ अपनी स्क्रिप्ट पर env जिस तरह से मैं देख रहा हूँ अपने env.1 सी

में

संपादित लिखना है: लगता है जैसे कोई मुझे ^^ मानना ​​है, तो मैं एक सरल और गंदा env.1.c लिखा है:

#include <stdlib.h> 
#include <stdio.h> 
#include <string.h> 
#include <unistd.h> 


const char* prependpath = "/your/prepend/path/here:"; 

int main(int argc, char** argv){ 
    int args_len = argc + 1; 
    char* args[args_len]; 
    const char* env = "/usr/bin/env"; 
    int i; 

    /* arguments: the same */ 
    args[0] = env; 
    for(i=1; i<argc; i++) 
    args[i] = argv[i]; 
    args[argc] = NULL; 

    /* environment */ 
    char* p = getenv("PATH"); 
    char* newpath = (char*) malloc(strlen(p) 
       + strlen(prependpath)); 
    sprintf(newpath, "%s%s", prependpath, p); 
    setenv("PATH", newpath, 1); 

    execv(env, args); 
    return 0; 
}