shell: 변수와 명령을 한줄에? 아울러 set, env, export 까지.

이 글이 정리가 잘 될 지도 의문이고, 제목부터 뭐라 정해야할 지도 애매하다.
발단은 IFS 에서부터 비롯됐다.

IFS 는 Shell Variable 로, 특수한 역할을 한다.
여기서, Shell Variable 과 Environment Variable 을 구분해야 한다.

셸 변수는 셸(bash, zsh 등등)에 의해 생성/관리되는 변수이고,
환경 변수는 그 외 모든 변수이다.

Bash Shell Variables 는 Man Page 의 Parameters 항목에서 찾을 수 있고, Environment Variables 는 터미널에서 printenv 명령으로 확인할 수 있다.


이제 다음과 같은 간단한 스크립트를 만든다.

#!/bin/bash
echo $abc

이 파일(run_test 라 명명)에 실행속성을 주고, 아래 명령을 실행한다.

$ abc="가나다라"
$ echo $abc
가나다라
$ ./run_test

더 이상할 것도 없다. $abc 는 셸 변수이고, echo 로 내용을 확인할 수 있다.
./run_test 의 결과는? 좀 헷갈린다.
run_test 내부에서 $abc 를 출력하라고 했는데, 아무것도 출력되지 않았다.
다음을 또 시험해보자.

$ abc="마바사아" ./run_test
마바사아
$ echo $abc
가나다라

?
한 줄로, 변수 할당 후 명령을 실행했다. 그랬더니, abc 변수가 생명을 이어갔다.
그런데, 다시 abc 를 출력했더니 “가나다라”가 살아났다.

이게 잘 이해가 되지 않는다. 명확한 설명이 있긴 한데, 봐도 확 눈에 들어오질 않는다.

The environment for any simple command or function may be augmented temporarily by prefixing it with parameter assignments, as described above in PARAMETERS. These assignment statements affect only the environment seen by that command.

Bash man page

어쨌든, 명령 앞에 변수를 할당하면, 그 명령에만 한정해서 변수가 살아있고, 명령이 끝나면 그 이전값으로 회귀한다고 한다.

위에서 언급한 IFS 는 공백, 탭 등등을 기본값으로 갖는데, 이걸 잠시 다른 값으로 할당하고 작업을 수행할 때 이렇게 수행해주면, 원래 값으로 쉽게 복귀할 수 있는 장점이 있다.

여기까지만 하면 이해가 될 듯도 한데, 다음 명령을 해보면 점점 더 헷갈리기만 하다.

$ abc="마바사아" echo $abc
가나다라

???
왜 ‘마바사아’가 아니고 다시금 ‘가나다라’가 된 걸까? 한 줄에 쓰면 다음 명령으로 넘어간다고 하지 않았나??
그에 대한 답을 찾긴 했는데..

위 글, 두번째 답변이 논리 정연하긴 하다.
다만, 내가 만든 예로 풀어보면, bash 는 $abc 를 먼저 확장(expand)하여 “” 로 만든 후 나머지를 진행한다고 하는데, 왜? 그러는 건지는 알 수가 없다. 그냥 원래 설계가 그렇다는 건지.
다른 답변들의 덧글들에서도 여러 논의가 있는데, 명확한 설명은 못찾겠다. (내가 이해를 못하는 건지..?)

어쨌든 의도한 결과를 얻기 위해선 이렇게 실행해야 한다고 한다.

$ abc="마바사아" bash -c 'echo $abc'
마바사아
$ abc="마바사아" eval 'echo $abc'
마바사아

알쏭달쏭.
잘 이해는 안가지만, 이렇게 내 맘대로 정리해볼 수는 있겠다.

abc="가나다라" 는 Shell Variable 이다.
일단 변수가 생성되고 난 뒤 echo 를 하면 당연히 abc 를 불러올 수 있다.
abc="마바사아" echo $abc 에서 abc 는 Environment Variable 이다. 이럴 경우, 먼저 명령이 실행되고, 나중에 환경변수가 할당이 된다. (그렇다고 해도, abc=”마바사아” bash -c ‘echo $abc’ 가 왜 실행이 되는 지는 여전히 알 길이 없다.. bash 가 먼저 뜨고, 환경변수를 읽은 후, echo $abc 를 실행하는 형국??)

다시 말하면, abc=”마바사아” echo $abc 에서 앞의 abc 는 환경변수, 뒤의 abc 는 셸변수다.
이 때, 셸 변수 abc 를 환경변수화 할 수는 없으려나?
여기서 export 가 등장한다.

export abc="마바사아"

그러나 이렇게 했다고 해서, 이게 시스템 전역에 영향을 미치지는 않는다.
다른 터미널을 열고 echo $abc 하면 여전히 아무 결과가 나오지 않는다.

export 의 역할은, 현재 프로세스에서 하위 프로세스까지 영향을 미치는 환경변수를 생성하는데 있다.

여기에서, 한걸음 더 나아가서, set, env, export 를 살펴보자.


env 는 이 글에 설명이 나오긴 하지만, 그냥 변수와 명령어를 한줄로 쓰는 것과 결과는 똑같다. 좀 더 확실한 예가 필요하다.
한가지 알아낸 사실은 env 는 셸 내부 명령이 아니고 외부 실행파일이라는 점 정도?

env 는 다음 글 첫번째 답변에 괜찮은(?) 설명이 있다.

정리하자면, env 는 Hashbang 행에서 주로 사용되고, 많이 쓰이지 않는다고 한다. Wine 실행 시에나, .desktop 파일을 만들 때에 간혹 env 가 쓰이는 것을 본 적이 있다. 저 글에서는 export 사용을 권장(?)하고 있다.
Thank you, Gilles!

set 은 env 와 유사한데, set 은 내부 명령이고, env 는 외부 명령이라는 글도 볼 수 있었다.

set/env 는 무시해도(잘 몰라도) 되겠다.

export 에 관한 내용은 위 본문에 간단히 언급/정리하긴 했으나, 보층 설명은 아래 글에서.

또 한 고비, 이렇게 넘는구나.

Tags:
2 Comments

안녕하세요. 글 남겨주셔서 고맙습니다.