환경 변수에 배열 값을 저장한 다음 Bash 스크립트에서 호출하는 해결 방법

환경 변수에 배열 값을 저장한 다음 Bash 스크립트에서 호출하는 해결 방법

"배열을 환경 변수로 사용한 다음 Bash 쉘 스크립트에서 호출할 수 있습니까?"라는 질문에 대한 답변을 찾아본 결과 "공식적으로" 지원되지 않는다는 결론을 내렸습니다(개요).여기, 그리고여기).

그러나 저는 이 작업을 꼭 수행해야 하며 "해결 방법"을 생각해 냈으므로 여러분의 의견을 듣고 싶습니다.

설정: 파일에 .profile다음과 같은 변수를 만들었습니다.

HOST_NAMES='server1 server2 server3'

그런 다음 쉘 스크립트 시작 부분에 다음과 같이 썼습니다.

SRVR_ARRAY=($(echo $HOST_NAMES | awk '{for (i = 1; i <=NF; i++) print $i " "}'))

스크립트 후반부에서 일부 작업을 수행해야 할 때 다음을 호출했습니다.

for h in "${SRVR_ARRAY[@]}"; do
ping $h
done

효과가 있었어요! 이제 나는 이것이 Bash 쉘 스크립트 jerry-riggin의 최고의 버전이라고 확신합니다. 그러나 누군가가 이 사용법으로 어떤 위험을 볼 수 있는지 알고 싶었습니까?

답변1

직면할 수 있는 문제는 분할 및 와일드카드와 같은 일반적인 문제입니다.

문자열은 별도의 배열 항목으로 분할되고 전역 문자( *?[])와 유사한 모든 항목이 일치하는 파일 이름으로 확장되므로 공백을 포함할 수 없습니다. 호스트 이름은 문제가 아닐 수도 있지만 일반적으로 그렇습니다.

이것은 자주 묻는 질문이며 반복적으로 논의됩니다. 쉘 변수의 확장과 glob 및 분할의 영향 그리고 bash/POSIX 쉘에서 변수를 인용하는 것을 잊어버리는 보안 위험


IFS이러한 문제를 해결하려면 a) 공백 이외의 항목을 설정하고 이를 사용하여 문자열을 구분하고 b) 를 비활성화해야 합니다 set -f.

이는 |구분 기호 역할을 하며 문자열을 분할합니다. 값에 원하지 않는 문자를 사용할 수 있습니다. \001( $'\001'Bash에서 이를 생성하는 데 사용되는)와 같은 일부 제어 문자도 사용할 수 있습니다.

#!/bin/bash
string='foo|bar'
IFS='|'; set -f
array=($string)        # split it

IFS='|'
string="${array[*]}"   # merge it back together

또한 주석에서 말했듯이 변수에 호스트 이름만 있고 공백으로 분할할 수 있는 경우 분할하기 위해 awk가 필요하지 않습니다. 쉘은 배열에 할당하거나 루프를 시작할 때 이 작업을 수행합니다.

SRVR_ARRAY=( $HOST_NAMES )
for x in $HOST_NAMES ; do ...

HOST_NAMES(역시 전역 문자를 포함하면 문제가 발생합니다.)

실제로 이는 귀하의 예에서도 발생합니다. awk무언가가 인쇄되고, 쉘이 이를 캡처하고, $()큰따옴표 안에 있지 않기 때문에 이를 단어로 분할한 다음, 단어를 개별적으로 배열에 저장합니다.

답변2

declare -p환경 변수에 출력을 저장할 수 있습니다 .

array=(foo 'bar baz'); array[12]=sparse
export ARRAY_definition="$(declare -p array)"

그런 다음 실행된 스크립트에서 다음을 수행합니다 bash.

eval "$ARRAY_definition"

eval와 동일한 로케일 declare(바람직하게는 동일한 버전 bash) 에서 실행하는 것이 중요합니다.

전역 범위에서 실행 되지 않으면 eval배열이 선언됩니다.현지의.

참조를 사용하면 zsh위험한 참조 사용을 피할 수 있습니다 eval.

export ARRAY_definition=${(j: :)${(q)array}}

수입:

array=(${(Q)${(z)ARRAY_definition}})

rces또는 이와 같은 것을 사용하거나 fish기본적으로 배열 내보내기를 지원하는 셸(자체 인코딩 사용)을 사용할 수 있습니다.

관련 정보