[bash] 환경 변수를 지정하고 동일한 명령 줄에서 에코 할 수없는 이유는 무엇입니까?

이 스 니펫을 고려하십시오.

$ SOMEVAR=AAA
$ echo zzz $SOMEVAR zzz
zzz AAA zzz

여기에 내가 설정 한 $SOMEVARAAA첫 번째 줄에 – 나는 두 번째 줄에 에코 때, 나는 도착 AAA예상대로 내용을.

그러나 다음과 같은 명령 줄에서 변수를 지정하려고하면 echo:

$ SOMEVAR=BBB echo zzz $SOMEVAR zzz
zzz AAA zzz

BBB예상대로 얻지 못함 -이전 값 ( AAA)을 얻습니다 .

이게 어떻게 돼야 돼? 그렇다면 어떻게 변수를 지정 LD_PRELOAD=/... program args ...하고 작동시킬 수 있습니까? 내가 무엇을 놓치고 있습니까?



답변

당신이 보는 것은 예상되는 행동입니다. 문제는 부모 쉘이$SOMEVAR 이 수정 된 환경에서 명령을 호출하기 전에 명령 줄에서 것입니다. $SOMEVAR환경이 설정 될 때까지 지연된 평가를 받아야합니다 .

즉각적인 옵션은 다음과 같습니다.

  1. SOMEVAR=BBB eval echo zzz '$SOMEVAR' zzz.
  2. SOMEVAR=BBB sh -c 'echo zzz $SOMEVAR zzz'.

둘 다 작은 따옴표를 사용하여 부모 쉘이 평가하지 못하도록합니다 $SOMEVAR. 환경에 설정된 후에 만 ​​평가됩니다 (일시적으로 단일 명령 기간 동안).

또 다른 옵션은 하위 쉘 표기법을 사용하는 것입니다 ( 마커스 쿤답변 에서 제안한 것처럼 ).

(SOMEVAR=BBB; echo zzz $SOMEVAR zzz)

변수는 하위 쉘에서만 설정됩니다.


답변

재검토 된 문제

솔직히, 매뉴얼은이 점에서 혼란 스럽습니다. GNU 배쉬 설명서는 말한다 :

간단한 명령 또는 함수 [내장을 제외 함]에 대한 환경은 쉘 매개 변수에 설명 된대로 매개 변수 지정을 접 두부로 추가하여 일시적으로 보강 할 수 있습니다. 이러한 할당 명령문은 해당 명령이 표시하는 환경에만 영향을줍니다.

실제로 문장을 구문 분석하면 명령 / 함수에 대한 환경 은 수정되지만 상위 프로세스의 환경은 수정되지 않습니다. 따라서 이것은 작동합니다.

$ TESTVAR=bbb env | fgrep TESTVAR
TESTVAR=bbb

env 명령이 실행되기 전에 환경이 수정 되었기 때문입니다. 그러나 이것은 작동하지 않습니다.

$ set -x; TESTVAR=bbb echo aaa $TESTVAR ccc
+ TESTVAR=bbb
+ echo aaa ccc
aaa ccc

매개 변수 확장이 쉘에 의해 수행 될 때 때문입니다.

통역사 단계

문제의 또 다른 부분은 Bash 가 인터프리터에 대해 다음 단계정의 한다는 것입니다 .

  1. 파일 (쉘 스크립트 참조), -c 호출 옵션에 인수로 제공된 문자열 (Bash 호출 참조) 또는 사용자 터미널에서 입력을 읽습니다.
  2. Quoting에 설명 된 인용 규칙에 따라 입력을 단어와 연산자로 나눕니다. 이러한 토큰은 메타 문자로 구분됩니다. 별칭 확장은이 단계에서 수행됩니다 (별칭 참조).
  3. 토큰을 단순 및 복합 명령으로 구문 분석합니다 (셸 명령 참조).
  4. 다양한 셸 확장 (셸 확장 참조)을 수행하여 확장 된 토큰을 파일 이름 목록 (파일 이름 확장 참조)과 명령 및 인수로 나눕니다.
  5. 필요한 리디렉션을 수행하고 (리디렉션 참조) 리디렉션 연산자와 해당 피연산자를 인수 목록에서 제거합니다.
  6. 명령을 실행합니다 (명령 실행 참조).
  7. 선택적으로 명령이 완료 될 때까지 대기하고 종료 상태를 수집합니다 (종료 상태 참조).

여기서 일어나는 일은 내장 기능이 자체 실행 환경을 얻지 못하므로 수정 된 환경을 볼 수 없다는 것입니다. 또한 간단한 명령 (예 : / bin / echo) 수정 된 환경 (env 예제가 작동 한 이유)을 얻지 만 쉘 확장은 4 단계 의 현재 환경에서 발생합니다.

즉, ‘aaa $ TESTVAR ccc’를 / bin / echo에 전달하지 않습니다. 보간 된 문자열 (현재 환경에서 확장 됨)을 / bin / echo에 전달합니다. 이 경우 현재 환경에 TESTVAR 이 없으므로 단순히 ‘aaa ccc’를 명령에 전달합니다.

요약

문서는 훨씬 더 명확 할 수 있습니다. 스택 오버플로가 있습니다!

또한보십시오

http://www.gnu.org/software/bash/manual/bashref.html#Command-Execution-Environment


답변

원하는 것을 얻으려면

( SOMEVAR=BBB; echo zzz $SOMEVAR zzz )

이유:

  • 다음 명령에서 세미콜론 또는 새 줄로 할당을 분리해야합니다. 그렇지 않으면 다음 명령 (echo)에 대한 매개 변수 확장이 발생 하기 전에 실행되지 않습니다 .

  • 현재 행을 넘어 지속되지 않도록하려면 서브 쉘 환경 내에서 할당 해야합니다.

이 솔루션은 다른 솔루션이 제안한 것보다 더 짧고 깔끔하며 효율적이며 특히 새로운 프로세스를 생성하지 않습니다.


답변

그 이유는 한 줄에 환경 변수를 설정하기 때문입니다. 그러나 echo확장을 bash하지 않습니다. 따라서, 귀하의 변수는 실제로 명령이 실행되기 전에, 비록 확장 SOME_VAR입니다 BBB에코 명령의 맥락에서.

효과를 확인하려면 다음과 같이 할 수 있습니다.

$ SOME_VAR=BBB bash -c 'echo $SOME_VAR'
BBB

여기서 변수는 하위 프로세스가 실행될 때까지 확장되지 않으므로 업데이트 된 값이 표시됩니다. SOME_VARIABLE부모 셸에서 다시 확인하면 AAA예상대로 여전히 입니다.


답변

SOMEVAR=BBB; echo zzz $SOMEVAR zzz

사용; 같은 줄에있는 문을 구분합니다.


답변

다음은 한 가지 대안입니다.

SOMEVAR=BBB && echo zzz $SOMEVAR zzz


답변