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


193

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

#!/bin/bash

TESTVARIABLE=hellohelloheloo
./test2.sh

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

#!/bin/bash

echo ${TESTVARIABLE}

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

다른 방법이 있습니까?


한 가지 아이디어는 변수를 파일에 저장 한 다음 다른 스크립트에로드하는 것입니다.
Rodrigo

@Rodrigo 나는 약간의 성공으로 스크립트 실행 사이에 값을 "저장"하기 위해 비슷한 접근법을 사용했다. 명심해야 할 것은 여러 개의 스크립트 인스턴스가 실행되면 문제가 발생할 수 있다는 것입니다. 그러나 bash 할당 형식으로 저장하면 파일을 가져와 변수를 가져올 수 있습니다.
FatalError

답변:


266

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

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


1
서브 쉘에 $ 1을 전달해야하는 경우 ( 'sudo sh -c ...'가 스크립트에서 호출되기 때문에)? $ 1을 환경 변수에 넣고 내보내고 명령에 변수를 사용해야합니까?
Urhixidur

sudo 액세스 권한이 필요한 경우 sudo -E ...를 사용하여 환경 변수를 보존 할 수 있습니다.
yucer

2
@FatalError ". ./b.sh"라고 부르는 마지막 a.sh의 마법을 설명해 주시겠습니까? 첫 번째 점의 의미는 무엇입니까? 그것은 훌륭한 btw를 작동합니다!
Deian

변수와 값을 파일로 설정하고 공유 할 수 있습니다
newshorts

@Deian, 기간 (도트)은 "소스"에 내장 된 bash에 대한 짧은 손입니다
Kirill Kost

27

치명적 오류는 간단한 가능성을 제공했습니다. 두 번째 스크립트를 작성하십시오! 이 두 번째 스크립트가 귀중한 변수 중 일부를 변경할 수 있다고 걱정되면 언제든지 서브 쉘에서 소스를 사용할 수 있습니다.

( . ./test2.sh )

괄호는 소스가 서브 쉘에서 발생하도록하므로 부모 쉘은 수정 test2.sh이 수행 될 수 있음을 알 수 없습니다 .


여기에서 분명히 참조해야 할 또 다른 가능성이 있습니다 : use set -a.

로부터 POSIX의 set참조 :

-a:이 옵션이 켜져 있으면 할당이 수행되는 각 변수에 대해 내보내기 속성이 설정됩니다. IEEE Std 1003.1-2001, 섹션 4.21, 변수 할당 의 기본 정의 볼륨을 참조하십시오 . 할당이 명령에서 유틸리티 이름 앞에 오는 경우, 유틸리티가 완료된 후 내보내기 속성이 현재 실행 환경에서 지속되지 않습니다. 단, 내장 된 특수 유틸리티 중 하나가 내장 속성 이후에 내보내기 속성이 지속되는 경우는 예외입니다 . 에 완료되었습니다. 지정이 명령에서 유틸리티 이름 앞에 오지 않거나 지정이 getopts 또는 read 조작의 결과 인 경우 유틸리티의 경우 변수가 설정 해제 될 때까지 내보내기 속성이 유지됩니다.

로부터 배쉬 설명서 :

-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

실제로 환경 변수를 수동으로 전달해도 괜찮다면 적어도 bash에서 내보내고 설정을 해제하거나 소싱하는 것보다 쉬운 방법이 있습니다.

a.sh를 보자

#!/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
Yo, lemme은 "내 윙클을 윙윙 거린다"고 말합니다. b.sh!
나는 "내 틴클을 흔들어"라고 들었어

마술은의 마지막 줄에 있으며 a.sh, 여기서 Message호출 기간 동안 만 from ./b.sh값으로 설정됩니다 . 기본적으로 명명 된 매개 변수 / 인수와 약간 비슷합니다. 그러나 그 외에도 응용 프로그램이 시작되는 X 서버를 제어 하는와 같은 변수에서도 작동합니다 .secreta.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

@gniourf_gniourf 서브 쉘로 소스하는 방법?
Toskan

@Toskan 이것은 내 대답에 언급되어 있습니다 : ( . ./test2.sh ). 괄호는 Bash가 서브 쉘에서 컨텐츠를 실행하게합니다.
gniourf_gniourf

7

Bash에서 표시된 것처럼 괄호를 사용하여 서브 쉘 내에서 변수를 내 보내면 내 보낸 변수가 누출되지 않습니다.

#!/bin/bash

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

여기서 장점은 명령 행에서 스크립트를 실행 한 후 $ TESTVARIABLE이 환경에 유출되지 않는다는 것입니다.

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

나는 그것을 사용했지만 작동하지 않는 것 같습니다-쓴 : (! 말한다 : ./script2.sh:No 파일 또는 디렉토리
Pranjal 굽타

최상위 환경 (명령 줄 $프롬프트)에는 내 보낸 내용 이 표시되지 않으므로 서브 쉘은 실제로 필요하지 않습니다 $TESTVARIABLE. 내보내기 는 변수 의 사본후속 하위 프로세스로 전달합니다. 스토리지에 값을 저장하고 나중에 상위 프로세스 스크립트에서 해당 스토리지를 읽는 경우를 제외하고 변수를 체인을 백업하여 상위 프로세스로 전달할 수 없습니다. 부모 스크립트의 두 번째 사본으로 파이핑 할 수는 있지만 동일한 프로세스 는 아닙니다 . 훌륭한 설명은 여기에서 찾을 수 있습니다 .
DocSalvager

2

다른 옵션은을 사용하는 것 eval입니다. 문자열을 신뢰할 수있는 경우에만 적합합니다. 첫 번째 스크립트는 변수 할당을 에코 할 수 있습니다.

echo "VAR=myvalue"

그때:

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

인에 대한 두 번째 스크립트는 환경 변수를 설정하고자 할 때이 방법은 특히 흥미 롭다 하지 bash는 당신이 또한 싶지 않아 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.bash는 작업을 계속합니다.

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.