एक शेल स्क्रिप्ट से दूसरे में सभी चर पास?


193

आइए बताते हैं कि मेरे पास एक शेल / बैश स्क्रिप्ट है जिसका नाम test.sh:

#!/bin/bash

TESTVARIABLE=hellohelloheloo
./test2.sh

मेरा test2.shऐसा दिखता है:

#!/bin/bash

echo ${TESTVARIABLE}

यह काम नहीं करता। मैं सभी वेरिएबल्स को मापदंडों के रूप में पारित नहीं करना चाहता क्योंकि imho यह ओवरकिल है।

क्या कोई अलग तरीका है?


एक विचार एक फ़ाइल में चर को बचाने और फिर किसी अन्य स्क्रिप्ट में लोड करने के लिए है।
रोड्रिगो

@ रोड्रिगो मैंने कुछ सफलता के साथ स्क्रिप्ट के रनों के बीच "बचत" मूल्यों के लिए एक समान दृष्टिकोण का उपयोग किया है। बस एक बात का ध्यान रखें, यदि स्क्रिप्ट के कई उदाहरण चलते हैं, तो चीजें पासा जा सकती हैं। लेकिन अगर आप उन्हें bash असाइनमेंट फॉर्म में सहेजते हैं, तो आप चर आयात करने के लिए फ़ाइल को केवल स्रोत कर सकते हैं
FatalError

जवाबों:


265

आपके पास मूल रूप से दो विकल्प हैं:

  1. export TESTVARIABLE2 स्क्रिप्ट को निष्पादित करने से पहले चर को एक पर्यावरण चर ( ) बनाएं ।
  2. दूसरा लिपि स्रोत, . test2.shऔर यह एक ही शेल में चलेगा। यह आपको सरणियों जैसे अधिक जटिल चर आसानी से साझा करने देगा, लेकिन इसका अर्थ यह भी है कि अन्य स्क्रिप्ट स्रोत शेल में चर को संशोधित कर सकती है।

अपडेट करें:

exportपर्यावरण चर सेट करने के लिए उपयोग करने के लिए, आप या तो मौजूदा चर का उपयोग कर सकते हैं:

A=10
# ...
export A

यह दोनों में bashऔर काम करना चाहिए shbashइसे भी इस तरह संयोजित करने की अनुमति देता है:

export A=10

यह मेरे sh (जो होता है bash, आप echo $SHELLजांचने के लिए उपयोग कर सकते हैं ) में भी काम करता है । लेकिन मुझे विश्वास नहीं है कि यह सभी में काम करने की गारंटी है sh, इसलिए इसे सुरक्षित रूप से खेलने और उन्हें अलग करने के लिए सबसे अच्छा है।

आपके द्वारा इस तरह निर्यात की जाने वाली कोई भी स्क्रिप्ट उदाहरण के लिए निष्पादित स्क्रिप्ट में दिखाई देगी:

a.sh:

#!/bin/sh

MESSAGE="hello"
export MESSAGE
./b.sh

b.sh:

#!/bin/sh

echo "The message is: $MESSAGE"

फिर:

$ ./a.sh
The message is: hello

तथ्य यह है कि ये दोनों शैल लिपियां भी सिर्फ आकस्मिक हैं। पर्यावरण चर को आपके द्वारा निष्पादित की जाने वाली किसी भी प्रक्रिया में पारित किया जा सकता है, उदाहरण के लिए यदि हम अजगर का उपयोग करते हैं, तो ऐसा लग सकता है:

a.sh:

#!/bin/sh

MESSAGE="hello"
export MESSAGE
./b.py

b.py:

#!/usr/bin/python

import os

print 'The message is:', os.environ['MESSAGE']

सोर्सिंग:

इसके बजाय हम इस तरह से स्रोत बना सकते हैं:

a.sh:

#!/bin/sh

MESSAGE="hello"

. ./b.sh

b.sh:

#!/bin/sh

echo "The message is: $MESSAGE"

फिर:

$ ./a.sh
The message is: hello

यह कम या ज्यादा b.shसीधे "की सामग्री" आयात करता है और इसे एक ही शेल में निष्पादित करता है । ध्यान दें कि हमें इसे एक्सेस करने के लिए वैरिएबल को एक्सपोर्ट नहीं करना था। यह आपके पास मौजूद सभी चर को साझा करता है, साथ ही साथ अन्य स्क्रिप्ट को शेल में वैरिएबल को जोड़ने / हटाने / संशोधित करने की अनुमति देता है। बेशक, इस मॉडल में आपकी दोनों स्क्रिप्ट एक ही भाषा ( shया bash) होनी चाहिए । एक उदाहरण देने के लिए कि हम संदेशों को आगे-पीछे कैसे कर सकते हैं:

a.sh:

#!/bin/sh

MESSAGE="hello"

. ./b.sh

echo "[A] The message is: $MESSAGE"

b.sh:

#!/bin/sh

echo "[B] The message is: $MESSAGE"

MESSAGE="goodbye"

फिर:

$ ./a.sh
[B] The message is: hello
[A] The message is: goodbye

इसमें समान रूप से अच्छी तरह से काम करता है bash। यह अधिक जटिल डेटा साझा करना भी आसान बनाता है जिसे आप पर्यावरण चर के रूप में व्यक्त नहीं कर सकते हैं (कम से कम अपने हिस्से पर कुछ भारी उठाने के बिना), जैसे कि सरणियाँ या साहचर्य सरणियाँ।


1
क्या होगा अगर मुझे उप-शेल में $ 1 पास करने की आवश्यकता है (क्योंकि 'sudo sh -c ...' को स्क्रिप्ट से कहा जाता है)? क्या मुझे पर्यावरण चर में $ 1 को अलग करना चाहिए, निर्यात करें और आदेश में चर का उपयोग करें?
उरिखीदुर

बस यह जोड़ने के लिए कि यदि आपको sudo एक्सेस अधिकारों की आवश्यकता है, तो आप sudo -E का उपयोग कर सकते हैं ... पर्यावरण चर को संरक्षित करने के लिए।
15

2
@FatalError क्या आप अंतिम a.sh में जादू की व्याख्या कर सकते हैं, जहाँ आप "./b.sh" कहते हैं। पहले डॉट का अर्थ क्या है? यह महान btw काम करता है!
दीया

आप चर और मानों को फ़ाइल में सेट कर सकते हैं और उन्हें इस तरह साझा कर सकते हैं
newshorts

@ डायन, द पीरियड (बिंदी) "स्रोत" में बनी बैश के लिए छोटा हाथ है
किरिल कोस्ट

27

घातक त्रुटि ने एक सीधी संभावना दी: स्रोत आपकी दूसरी स्क्रिप्ट! यदि आप चिंतित हैं कि यह दूसरी स्क्रिप्ट आपके कुछ कीमती चरों को बदल सकती है, तो आप इसे हमेशा एक सबस्क्रिप्शन में ही स्रोत बना सकते हैं:

( . ./test2.sh )

कोष्ठक स्रोत को एक उप-क्रम में बना देगा, जिससे कि माता-पिता खोल नहीं देख पाएंगे कि संशोधन test2.shप्रदर्शन कर सकते हैं।


एक और संभावना है जिसे निश्चित रूप से यहां संदर्भित किया जाना चाहिए: उपयोग set -a

से POSIX setसंदर्भ :

-a: जब यह विकल्प चालू होता है, तो निर्यात विशेषता प्रत्येक चर के लिए निर्धारित की जाएगी , जिसके लिए एक असाइनमेंट किया जाता है; IEEE Std 1003.1-2001, धारा 4.21, चर असाइनमेंट का आधार परिभाषा खंड देखें । यदि असाइनमेंट एक कमांड में एक उपयोगिता नाम से पहले होता है, तो निर्यात विशेषता वर्तमान निष्पादन वातावरण में उपयोगिता के पूरा होने के बाद बनी नहीं रहेगी, इस अपवाद के साथ कि विशेष निर्मित उपयोगिताओं में से एक से पहले निर्यात विशेषता निर्मित होने के बाद भी बनी रहती है। में पूरा किया है। यदि असाइनमेंट कमांड में एक उपयोगिता नाम से पहले नहीं है, या यदि असाइनमेंट गेटटॉप या पढ़ने के संचालन का एक परिणाम है उपयोगिताओं, निर्यात विशेषता तब तक बनी रहेगी जब तक कि चर अप्रभावित न हो।

से बैश मैनुअल :

-a: मार्क वैरिएबल और फ़ंक्शन जो बाद के कमांड के वातावरण में निर्यात के लिए संशोधित या बनाए जाते हैं।

तो आपके मामले में:

set -a
TESTVARIABLE=hellohelloheloo
# ...
# Here put all the variables that will be marked for export
# and that will be available from within test2 (and all other commands).
# If test2 modifies the variables, the modifications will never be
# seen in the present script!
set +a

./test2.sh

 # Here, even if test2 modifies TESTVARIABLE, you'll still have
 # TESTVARIABLE=hellohelloheloo

ध्यान दें कि चश्मा केवल निर्दिष्ट करते हैं कि निर्यात के लिए set -aचर के साथ चिह्नित है। अर्थात्:

set -a
a=b
set +a
a=c
bash -c 'echo "$a"'

गूंज उठेगा cऔर न ही एक खाली रेखा और न ही b(जो set +aनिर्यात के लिए अचिह्नित नहीं है, और न ही यह केवल निर्यात किए गए पर्यावरण के लिए असाइनमेंट के मूल्य को "सहेजना" है)। यह, ज़ाहिर है, सबसे प्राकृतिक व्यवहार है।

निष्कर्ष: का उपयोग कर set -a/ set +aमैन्युअल रूप से सभी चर निर्यात की तुलना में कम थकाऊ हो सकता है। यह दूसरी लिपि की सोर्सिंग से बेहतर है, क्योंकि यह किसी भी कमांड के लिए काम करेगा, न कि उसी शेल लैंग्वेज में लिखे गए।


18

वास्तव में निर्यात करने और परेशान करने या फिर से सोर्सिंग करने का एक आसान तरीका है (कम से कम बाश में, जब तक आप पर्यावरण चर को मैन्युअल रूप से पारित करने के साथ ठीक नहीं हो जाते):

चलो

#!/bin/bash
secret="winkle my tinkle"
echo Yo, lemme tell you \"$secret\", b.sh!
Message=$secret ./b.sh

और b.sh हो

#!/bin/bash
echo I heard \"$Message\", yo

देखा गया आउटपुट है

[rob @ Archie test] $ ./a.sh
यो, lemme आपको "विंक माय टिंकल", b.sh!
मैंने सुना "विंक माय टिंकल", यो

जादू की आखिरी पंक्ति में निहित है a.sh, जहां Message, के आह्वान की अवधि के लिए ./b.sh, से मूल्य पर सेट किया गया secretहै a.sh। असल में, यह नामांकित मापदंडों / तर्कों की तरह है। हालांकि, इससे भी अधिक, यह यहां तक ​​कि चर के लिए भी काम करता है $DISPLAY, जो एक्स सर्वर एक एप्लिकेशन में शुरू होता है, को नियंत्रित करता है।

याद रखें, पर्यावरण चर की सूची की लंबाई अनंत नहीं है। अपेक्षाकृत वेनिला कर्नेल के साथ मेरे सिस्टम पर, xargs --show-limitsमुझे बताता है कि दलीलों का अधिकतम आकार बफर 2094486 बाइट्स है। सैद्धांतिक रूप से, आप शेल स्क्रिप्ट का गलत उपयोग कर रहे हैं यदि आपका डेटा किसी से भी बड़ा है (पाइप, कोई भी?)


7

फैटल एरर के उत्तर को जोड़ते हुए, चर को किसी अन्य शेल स्क्रिप्ट में पास करने का एक और तरीका है।

उपर्युक्त सुझाए गए समाधान में कुछ कमियां हैं:

  1. using Export : यह चर को उनके दायरे से बाहर प्रस्तुत करने का कारण होगा जो एक अच्छा डिजाइन अभ्यास नहीं है।
  2. using Source : इसका कारण कुछ अन्य शेल स्क्रिप्ट फ़ाइल में पूर्वनिर्धारित चर की नाम टक्कर या आकस्मिक ओवरराइटिंग हो सकती है, जिसमें किसी अन्य फ़ाइल का स्रोत है।

हमारे लिए उपयोग करने के लिए एक और सरल उपाय उपलब्ध है। आपके द्वारा पोस्ट किए गए उदाहरण को ध्यान में रखते हुए,

test.sh

#!/bin/bash

TESTVARIABLE=hellohelloheloo
./test2.sh "$TESTVARIABLE"

test2.sh

#!/bin/bash

echo $1

उत्पादन

hellohelloheloo

यह भी ध्यान रखना महत्वपूर्ण है कि ""यदि हम मल्टीवर्ड स्ट्रिंग्स पास करते हैं तो यह आवश्यक है। एक और उदाहरण लेते हुए

master.sh

#!/bin/bash
echo in master.sh
var1="hello world"
sh slave1.sh $var1
sh slave2.sh "$var1"
echo back to master

slave1.sh

#!/bin/bash
echo in slave1.sh
echo value :$1

slave2.sh

#!/bin/bash
echo in slave2.sh
echo value : $1

उत्पादन

in master.sh
in slave1.sh
value :"hello
in slave2.sh
value :"hello world"

यह इस लिंक में उपयुक्त रूप से वर्णित कारणों के कारण होता है


6
का उपयोग sourceवास्तव में एक अच्छी बात है। अपनी चिंता के बारे में: पूर्वनिर्धारित चर की आकस्मिक ओवरराइटिंग , आप हमेशा एक उप-स्रोत में स्रोत कर सकते हैं। यह समस्या को पूरी तरह हल करता है।
गनीउर्फ़_ग्निउरफ़

@gniourf_gniourf कैसे एक उपधारा में स्रोत के लिए?
तोशांक

@Toskan यह मेरे जवाब में उल्लेख किया गया है ( . ./test2.sh ):। कोष्ठक बाश को अपनी सामग्री को एक उपधारा में चलाएगा।
गनीउर_ग्निउरफ

7

बैश में यदि आप एक उपधारा के भीतर चर का निर्यात करते हैं, तो दिखाए गए कोष्ठक का उपयोग करके, आप निर्यात किए गए चर को लीक करने से बचते हैं:

#!/bin/bash

TESTVARIABLE=hellohelloheloo
(
export TESTVARIABLE    
source ./test2.sh
)

यहाँ लाभ यह है कि कमांड लाइन से स्क्रिप्ट चलाने के बाद, आपको अपनी प्रकृति में $ TESTVARIABLE लीक नहीं होगा:

$ ./test.sh
hellohelloheloo
$ echo $TESTVARIABLE
                            #empty! no leak
$

मैंने इसका उपयोग किया था, लेकिन यह काम नहीं करता है- मैंने लिखा है: #! / Bin / bash for ((i = 1; i <= 3; i ++)) do (Export i source ./script2.sh) ने ERROR किया। कहते हैं :/script2.sh: कोई ऐसी फ़ाइल या निर्देशिका नहीं है
प्रांजल गुप्ता

शीर्ष-स्तरीय वातावरण (कमांडलाइन $प्रॉम्प्ट) के बाद से सबस्क्रिप्शन की आवश्यकता नहीं है, कभी भी निर्यात नहीं देखा जाएगा $TESTVARIABLE। निर्यात बस किसी भी बाद की बच्चे प्रक्रियाओं के लिए एक चर की एक प्रति से गुजरता है। पैरेंट प्रोसेस स्क्रिप्ट में स्टोरेज और बाद में उस स्टोरेज को पढ़ने के लिए वैल्यू सेव करके छोड़कर वेरिएबल्स को पैरेंट प्रॉसेस तक चेन को पास करना संभव नहीं है। मूल स्क्रिप्ट की दूसरी प्रति के लिए पाइपिंग संभव है लेकिन यह एक ही प्रक्रिया नहीं होगी । एक उत्कृष्ट स्पष्टीकरण यहाँ पाया जा सकता है
DocSalvager

2

एक अन्य विकल्प का उपयोग कर रहा है eval। यह केवल तभी उपयुक्त है जब तारों पर भरोसा किया जाता है। पहली स्क्रिप्ट चर असाइनमेंट को प्रतिध्वनित कर सकती है:

echo "VAR=myvalue"

फिर:

eval $(./first.sh) ./second.sh

यह दृष्टिकोण विशेष रुचि का है जब आप जिस दूसरी स्क्रिप्ट के लिए पर्यावरण चर निर्धारित करना चाहते हैं वह बाश में नहीं है और आप exportचर भी नहीं चाहते हैं , शायद इसलिए कि वे संवेदनशील हैं और आप नहीं चाहते कि वे बने रहें।


1

एक और तरीका, जो मेरे लिए थोड़ा आसान है, नामांकित पाइप का उपयोग करना है। नामित पाइपों ने विभिन्न प्रक्रियाओं के बीच संदेशों को सिंक्रनाइज़ करने और भेजने का एक तरीका प्रदान किया।

A.bash:

#!/bin/bash
msg="The Message"
echo $msg > A.pipe

B.bash:

#!/bin/bash
msg=`cat ./A.pipe`
echo "message from A : $msg"

उपयोग:

$ mkfifo A.pipe #You have to create it once
$ ./A.bash & ./B.bash # you have to run your scripts at the same time

B.bash संदेश की प्रतीक्षा करेगा और जैसे ही A.bash संदेश भेजेगा, B.ash अपना कार्य जारी रखेगा।

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