Bash(또는 기타)에서 변수 환경 변수 설정

Bash(또는 기타)에서 변수 환경 변수 설정

내 스크립트에서 설정할 환경 변수의 키/값 쌍이 포함된 파일을 읽은 다음 설정하도록 하려고 합니다.

지금까지 나는 이것을 가지고 있습니다 :

#!/bin/bash

cat $1 | while read kv
do
    key=${kv%=*}
    val=`echo ${kv#*=} | sed 's/^"\|"$//g'`
    export $key="$val"
done

다음과 같은 파일을 읽고 싶습니다.

XAUTHLOCALHOSTNAME="localhost"
DISPLAY=":0"
XAUTHORITY="/tmp/some-XAuthority"

스크립트가 실행되는 동안에만 이 변수를 사용하면 되므로 다음 문제를 해결할 필요가 없습니다.스크립트에서 상위 범위에 대한 변수 설정.

내 테스트에 따르면 내 문제는 다음과 같습니다 export $key="$val". 따라서 해당 와이어를 교체하면 될 것 같습니다.

답변1

export $key=$val잘 작동할 것입니다 bash. 귀하의 문제는 파이프( )인 것 같습니다 |. 파이프라인의 모든 명령은 서브셸에서 실행됩니다. 예제에서 스크립트를 실행하는 인스턴스는 bash2개의 하위 셸(하나는 for, cat $1하나는 for) 을 분기합니다 while read .... 변수는 while 루프를 실행하는 하위 셸에 할당되고 내보내지며, 하위 셸이 종료되면 모든 변수가 즉시 발생합니다. 이 문제를 해결하는 한 가지 방법은 하위 쉘을 전혀 생성하지 않는 것입니다. 바꾸다고양이의 쓸모없는 사용, 리디렉션해 보세요:

while read ...; do
   ...
done < "$1"

배쉬 FAQ 24이에 대해 더 자세히 설명되어 있습니다.

또 다른 방법은 파일 소스를 가져와서 내보내기를 추가하는 것입니다.

. <(sed '/^export/!s/^/export /' "$1")

이것이 <( )프로세스 대체입니다.

주목해야 할 또 다른 점은 매개변수에서 환경 변수를 읽기 때문에 매개변수 파일이 $1스크립트에 나쁜 영향을 미치지 않도록 신뢰할 수 있는 소스인지 확인해야 한다는 것입니다.

답변2

(jw013이 정답을 제시했습니다, 하지만 더 많은 문제를 지적하고 싶습니다. )

파이프의 오른쪽은 bash(및 ATT ksh 및 zsh를 제외한 대부분의 다른 쉘)의 자체 하위 쉘에서 실행됩니다. 따라서 메인 셸 프로세스가 아닌 루프를 실행하는 하위 셸에서 환경 변수를 설정합니다.

다음은 간단한 수정 방법입니다. cat쓸모없는 사용을 리디렉션으로 바꾸면 됩니다.

while read …; do …; done <"$1"

일반적으로 입력을 전처리해야 하는 경우 루프와 스크립트의 나머지 부분(적어도 변수를 변경해야 하는 부분)을 블록에 넣습니다.

grep '^foo_' "$1" | {
  while read …; do …; done
  do_something
}

일반적으로 while read line; do …입력 행은 완전히 반복되지 않습니다. 바라보다while IFS= read대신 왜 그렇게 자주 사용됩니까 IFS=; while read..?설명을 위해. 입력 행을 반복하는 올바른 관용구는 다음과 같습니다.

while IFS= read -r line; do …

여기서 선행 및 후행 공백을 제거하는 것은 주어진 예제 입력의 경우가 아니기 때문에 중요하지 않지만 -r백슬래시 확장을 피하는 것이 좋습니다. 이것은 while read line실제로 입력을 읽는 올바른 방법일 수 있습니다(그러나 변수 값에 개행 문자가 포함되지 않은 경우에만 의심됩니다). 입력 형식이 모호하거나 구문 분석하기가 더 복잡할 수도 있습니다. 변수 값 중 하나에 개행 문자, 큰따옴표 또는 백슬래시가 포함되어 있으면 어떻게 되는지 확인하세요.

입력이 확실히 중단되는 지점은 값을 추출할 때입니다.

val=`echo ${kv#*=} | sed 's/^"\|"$//g'`

먼저 변수 대체 주위에 큰따옴표를 사용해야 합니다. echo "${kv#*=}"그렇지 않으면 쉘이 토큰화 및 파일 이름 생성(즉, 와일드카드 지정)을 수행합니다. 둘째, a로 시작하는 일부 문자열은 옵션으로 처리되고 일부 쉘은 인수에 대해 백슬래시 확장을 수행하므로 echo이는 문자열을 인쇄하는 신뢰할 수 있는 방법이 아닙니다 . -문자열을 인쇄하는 안정적이고 이식 가능한 방법은 입니다 printf %s "${kv#*=}". 또한 값이 여러 줄에 걸쳐 있으면 sed 프로그램은 각 줄에서 개별적으로 작동합니다. 이는 잘못된 것입니다. 이 문제는 고칠 수 있지만 더 쉬운 방법이 있습니다. 즉, 셸의 문자열 조작 도구인 를 사용하는 것입니다 val=${kv#*=}; val=${val#\"}; val=${val%\"}.

입력이 plain 을 사용하여 올바르게 구문 분석되었다고 가정하면 각 줄을 분할하는 설정을 read활용하여 구문 분석하는 더 쉬운 방법이 있습니다 .IFS

while read name value; do
  value=${value#\"}; value=${value%\"}
  export name="$value"
done <"$1"

답변3

export또 다른 좋은 옵션은 파일에 넣고 가져오는 것입니다 .

export XAUTHLOCALHOSTNAME="localhost"
export DISPLAY=":0"
export XAUTHORITY="/tmp/some-XAuthority"

그런 다음:

. "$1"

답변4

사용eval구조(나에게 도움이 됨):

key=andre  # Set the key
val=3000   # Set the value

eval "export ${key}=${val}";

echo $andre # Prints 3000

관련 정보