Programing

한 쉘 스크립트에서 다른 쉘 스크립트로 모든 변수를 전달 하시겠습니까?

crosscheck 2020. 5. 25. 21:00
반응형

한 쉘 스크립트에서 다른 쉘 스크립트로 모든 변수를 전달 하시겠습니까?


쉘 / bash 스크립트가 있다고 가정 해 보겠습니다 test.sh.

#!/bin/bash

TESTVARIABLE=hellohelloheloo
./test2.sh

test2.sh모습은 다음과 같습니다.

#!/bin/bash

echo ${TESTVARIABLE}

작동하지 않습니다. imho 이것은 과잉이기 때문에 모든 변수를 매개 변수로 전달하고 싶지 않습니다.

다른 방법이 있습니까?


기본적으로 두 가지 옵션이 있습니다.

  1. export TESTVARIABLE두 번째 스크립트를 실행하기 전에 변수를 환경 변수 ( )로 만드십시오 .
  2. 두 번째 스크립트의 소스를 지정하십시오. 즉 . test2.sh, 동일한 쉘에서 실행됩니다. 이렇게하면 배열과 같이보다 복잡한 변수를 쉽게 공유 할 수 있지만 다른 스크립트는 소스 셸에서 변수를 수정할 수 있습니다.

최신 정보:

사용하려면 export환경 변수를 설정하려면, 당신도 기존 변수를 사용할 수 있습니다 :

A=10
# ...
export A

이것은 모두에서 작동한다고 bash하고 sh. bash또한 다음과 같이 결합 할 수 있습니다.

export A=10

이것은 또한 작동 sh (될 일이있는 bash, 당신이 사용할 수있는 echo $SHELL체크). 그러나 나는 sh그것이 모두 에서 작동한다고 보장하지 않으므로 안전하고 분리하는 것이 가장 좋습니다.

이 방법으로 내 보낸 변수는 다음과 같이 실행하는 스크립트에 표시됩니다.

금연 건강 증진 협회:

#!/bin/sh

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

b.sh :

#!/bin/sh

echo "The message is: $MESSAGE"

그때:

$ ./a.sh
The message is: hello

이것들이 둘 다 쉘 스크립트라는 사실은 단지 부수적입니다. 환경 변수는 실행하는 모든 프로세스에 전달 될 수 있습니다. 예를 들어 파이썬을 대신 사용하면 다음과 같이 보일 수 있습니다.

금연 건강 증진 협회:

#!/bin/sh

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

b.py :

#!/usr/bin/python

import os

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

소싱 :

대신 다음과 같이 소스를 사용할 수 있습니다.

금연 건강 증진 협회:

#!/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) 여야합니다 . 메시지를주고받을 수있는 방법을 예를 들어 보려면 :

금연 건강 증진 협회:

#!/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. 또한 배열이나 연관 배열과 같이 환경 변수로 표현할 수없는 복잡한 데이터를 쉽게 공유 할 수 있습니다.


Fatal Error gave a straightforward possibility: source your second script! if you're worried that this second script may alter some of your precious variables, you can always source it in a subshell:

( . ./test2.sh )

The parentheses will make the source happen in a subshell, so that the parent shell will not see the modifications test2.sh could perform.


There's another possibility that should definitely be referenced here: use set -a.

From the POSIX set reference:

-a: When this option is on, the export attribute shall be set for each variable to which an assignment is performed; see the Base Definitions volume of IEEE Std 1003.1-2001, Section 4.21, Variable Assignment. If the assignment precedes a utility name in a command, the export attribute shall not persist in the current execution environment after the utility completes, with the exception that preceding one of the special built-in utilities causes the export attribute to persist after the built-in has completed. If the assignment does not precede a utility name in the command, or if the assignment is a result of the operation of the getopts or read utilities, the export attribute shall persist until the variable is unset.

From the Bash Manual:

-a: Mark variables and function which are modified or created for export to the environment of subsequent commands.

So in your case:

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

Observe that the specs only specify that with set -a the variable is marked for export. That is:

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

will echo c and not an empty line nor b (that is, set +a doesn't unmark for export, nor does it “save” the value of the assignment only for the exported environment). This is, of course, the most natural behavior.

Conclusion: using set -a/set +a can be less tedious than exporting manually all the variables. It is superior to sourcing the second script, as it will work for any command, not only the ones written in the same shell language.


There's actually an easier way than exporting and unsetting or sourcing again (at least in bash, as long as you're ok with passing the environment variables manually):

let a.sh be

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

and b.sh be

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

Observed output is

[rob@Archie test]$ ./a.sh
Yo, lemme tell you "winkle my tinkle", b.sh!
I heard "winkle my tinkle", yo

The magic lies in the last line of a.sh, where Message, for only the duration of the invocation of ./b.sh, is set to the value of secret from a.sh. Basically, it's a little like named parameters/arguments. More than that, though, it even works for variables like $DISPLAY, which controls which X Server an application starts in.

Remember, the length of the list of environment variables is not infinite. On my system with a relatively vanilla kernel, xargs --show-limits tells me the maximum size of the arguments buffer is 2094486 bytes. Theoretically, you're using shell scripts wrong if your data is any larger than that (pipes, anyone?)


In Bash if you export the variable within a subshell, using parentheses as shown, you avoid leaking the exported variables:

#!/bin/bash

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

The advantage here is that after you run the script from the command line, you won't see a $TESTVARIABLE leaked into your environment:

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

Adding to the answer of Fatal Error, There is one more way to pass the variables to another shell script.

The above suggested solution have some drawbacks:

  1. using Export : It will cause the variable to be present out of their scope which is not a good design practice.
  2. using Source : It may cause name collisions or accidental overwriting of a predefined variable in some other shell script file which have sourced another file.

There is another simple solution avaiable for us to use. Considering the example posted by you,

test.sh

#!/bin/bash

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

test2.sh

#!/bin/bash

echo $1

output

hellohelloheloo

Also it is important to note that "" are necessary if we pass multiword strings. Taking one more example

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

output

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

It happens because of the reasons aptly described in this link


Another way, which is a little bit easier for me is to use named pipes. Named pipes provided a way to synchronize and sending messages between different processes.

A.bash:

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

B.bash:

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

Usage:

$ 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 will wait for message and as soon as A.bash sends the message, B.bash will continue its work.


Another option is using eval. This is only suitable if the strings are trusted. The first script can echo the variable assignments:

echo "VAR=myvalue"

Then:

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

This approach is of particular interest when the second script you want to set environment variables for is not in bash and you also don't want to export the variables, perhaps because they are sensitive and you don't want them to persist.

참고URL : https://stackoverflow.com/questions/9772036/pass-all-variables-from-one-shell-script-to-another

반응형