bash - 자체 네임스페이스를 오염시키지 않는 소스 코드 [다른 스크립트에서 변수를 가져오는 안전한 방법]

bash - 자체 네임스페이스를 오염시키지 않는 소스 코드 [다른 스크립트에서 변수를 가져오는 안전한 방법]

다른 bash 스크립트의 변수 내용을 호출 스크립트의 변수에 할당하고 싶습니다.

특히 다음 파일이 있습니다 source.https://projects.archlinux.org/svntogit/packages.git/plain/trunk/PKGBUILD?h=packages/firefox(및 기타 유사한 문서).

파일에는 등의 변수가 포함되어 있습니다 depends.makedepends

그래서 내 스크립트에는 다음과 같은 여러 문이 있습니다.

depends="$(source "/path/to/file" ; printf '%s' "${depends[@]}")"
makedepends="$(source "/path/to/file" ; printf '%s' "${makedepends[@]}")"
...

따라서 기본적으로 각 명령문은 파일을 가져오고 내용을 인쇄하는 자체 하위 쉘을 시작합니다.단 하나의 변수상위 쉘의 변수에.

단일 서브쉘을 시작하는 것과 관련된 다른 방법이 있습니까?, 파일을 가져오고 호출 셸에 지정된 파일에 할당된 지정된 변수의 내용을 가져옵니다.쉘이 호출되는 환경을 오염시키지 않습니까?

------------------------------------- ----------

Mark Mann이 외국 스크립트 사용의 위험성을 지적했기 때문에 source나는 결국 다른 해결책을 제안하게 되었습니다. source이를 사용하여 다른 스크립트의 변수(varName=(...),varName2="...",varname3 ='... ',varName4=...)와 결과를 얻는 대신 :grepperleval

$ grepvars='(license)|(depends)|(makedepends)|(url)|(pkgdesc)|(pkgver)'
$
$ eval $(grep -Pzo "^(${grepvars})=\([^\)\(\`]*\)|^(${grepvars})=\"[^\"\(\`]*\"|^(${grepvars})='\''[^'\'']*'\''|^(${grepvars})=[^\s;\(\`]*" /tmp/above_mentioned_file)
$ echo $url
https://www.mozilla.org/firefox/
$
$ echo ${depends[@]}
gtk3 gtk2 mozilla-common libxt startup-notification mime-types dbus-glib alsa-lib ffmpeg2.8 desktop-file-utils hicolor-icon-theme libvpx icu libevent nss hunspell sqlite ttf-font

답변1

사용 eval.

소스 코드가 있는 경우(/tmp/other.sh에):

a=1
b=2
c=3

일부만 필요한 경우 이를 사용하여 eval항목을 가져올 수 있습니다(/tmp/main.sh에서).

eval $(source /tmp/other.sh;
       echo a="$a";
       echo b="$b";)

echo a is $a "(expect 1)"
echo b is $b "(expect 2)"
echo c is $c "(expect nothing)"

그리고 실행하세요:

$ bash /tmp/main.sh
a is 1 (expect 1)
b is 2 (expect 2)
c is (expect nothing)

경고하다: 신뢰할 수 없는 스크립트를 실행 eval하거나 실행하는 source것은 매우 위험합니다. 당신은 쉘 스크립트를 실행하고 있으며 스크립트는 당신이 스스로 할 수 있는 모든 것을 할 수 있습니다.경고하다

답변2

또는 이와 유사한 것을 사용하는 경우 다음을 eval사용하지 않는 경우에도 프로세스 대체를 통해 이 작업을 수행할 수 있습니다.bash

source <(source "/path/to/file" ; printf %s\\n "depends=${depends[*]}" "makedepends=${makedepends[*]}")

이는 초기 예제와 마찬가지로 서브셸을 시작하고 파일을 가져오지만 값을 직접 인쇄하고 명령 대체를 사용하는 대신 할당된 형식의 값을 인쇄하고 프로세스 대체를 사용하여 출력을 얻습니다.

이는 귀하의 질문의 다음 부분에 대한 완전한 답변입니다.

호출 셸의 환경을 오염시키지 않고 단일 하위 셸을 시작하고, 파일을 가져오고, 호출 셸에 지정된 파일에 할당된 지정된 변수의 내용을 가져오는 것과 관련된 다른 방법이 있습니까?

하지만 물론외국 스크립트를 소싱하는 데에는 위험이 남아 있습니다. 신뢰할 수 없는 스크립트를 절대로 얻지 마십시오.

대본을 직접 작성하셨다면절대적으로 확신부작용이 없고 출력도 생성되지 않으면 위의 내용을 사용할 수 있습니다.나만의 PC. 이건 해서는 안되는 일이 아니야한 번프로덕션 스크립트에서. 매우 큰 보안 결함입니다.

답변3

source <(cat "/path/to/file" | grep "depends\|makedepends")

소스가 전혀 없습니다 /path/to/file(와일드카드 접근 방식과 비교). 불안정성에 대한 위의 논의를 참조하세요. 또한 .env파일이나 이와 유사한 파일 인 경우 docker-compose인용되지 않은 변수를 실행하지 않고 변수를 플롯하는 방식으로 다른 스크립트에서 사용할 수 있어 실행 오류가 발생할 수 있습니다. 예를 들어 traefik이와 같은 프런트엔드 규칙은 WEB_FRONTEND_RULE=Host:my.host.name;PathPrefix:/my-path-prefix에서는 작동 docker-compose .env하지만 소스에서는 작동하지 않습니다 bash. WEB_FRONTEND_RULE='Host:my.host.name;PathPrefix:/my-path-prefix'from 에서는 유효하지만 에서는 유효 하지 bash않습니다 docker-compose .env.

답변4

확장됨답변와일드카드에서 및 파일을 가져온 후(모두 동일한 경고는 다음과 같은 경우에만 표시됩니다.믿다파일), 스캔하여 내보낸 변수 이름을 식별하고 해당 선언을 가져온 다음 다시 내보낼 수 있습니다.

source-export() {
  local _RC=0
  local FILENAME=$1
  shift
  source <(
    source "${FILENAME}" "$@"
    _RC=$?
    if (( _RC )); then
      typeset -p _RC
      exit
    fi
    # show the exported names
    PATTERN="\b(?<=export)(\s+\w+)+"
    while read -r NAME; do
      [[ -n ${NAME} ]] && typeset -p "${NAME}"
    done < <(grep -oP "${PATTERN}" "${FILENAME}" | tr ' ' '\n')
  )
  return ${_RC}
}

참고: 내보내기를 위해 스캔하는 데 사용하는 모드는 상당히 강력해야 합니다(유사한 상황 처리 export A B). 잠재적으로 더 강력한 또 다른 접근 방식은 파생 변수를 획득하기 전과 후에 변수 테이블을 구별하는 것입니다.

예:

$ cat foo.sh
export XXX="432"
YYY=111
export ZZZ="'adfa $*"
export A B
A=1
B=2
C=3

$ source-export foo.sh 3 2 1
$ echo -e "XXX=$XXX\nYYY=$YYY\nZZZ=$ZZZ\nA=$A\nB=$B\nC=$C"
XXX=432
YYY=
ZZZ='adfa 3 2 1
A=1
B=2
C=

비교적:

$ source foo.sh 3 2 1
$ echo -e "XXX=$XXX\nYYY=$YYY\nZZZ=$ZZZ\nA=$A\nB=$B\nC=$C"
XXX=432
YYY=111
ZZZ='adfa 3 2 1
A=1
B=2
C=3

및 에서 bash테스트되었습니다 zsh.

관련 정보