본문으로 건너뛰기

환경 변수와 셸 스크립트

정보처리기사 목차운영체제: 메모리와 명령어레슨 165 / 233

목차

환경 변수(environment variable)는 셸과, 셸이 실행하는 프로그램이 함께 보는 이름=값 쌍입니다. env·set·export로 보고 바꾸며, 명령을 찾을 디렉터리를 적은 PATH가 대표입니다. 셸 스크립트(shell script)는 셸 명령을 파일에 적어 차례로 실행하게 한 것으로, 변수·조건·반복을 씁니다.

리눅스 기본 명령어에서 ls라고만 쳤는데, 셸은 어디에 있는 ls를 실행했을까요? 셸은 PATH라는 환경 변수에 적힌 디렉터리를 뒤져 찾습니다. 같은 명령을 매번 치는 대신 파일에 적어 두면 셸 스크립트가 되고, 실행 권한은 파일 권한과 링크에서 본 chmod로 줍니다. 아래 그림은 변수가 자식 프로세스로 전해지는 모습과, 셸이 PATH의 디렉터리를 차례로 뒤져 실행 파일을 찾는 과정을 보입니다.

6단계 중 1단계. 이름=값으로 만든 변수는 그 셸 안에서만 쓰입니다. export 한 변수는 환경 변수가 되어, 셸이 실행하는 프로그램에도 전해집니다.

1셸 변수와 환경 변수 — env·set·export

셸에서 이름=값으로 만든 변수는 셸 변수입니다. 그 셸 안에서만 쓰이고, 셸이 실행하는 프로그램(자식 프로세스)에는 전해지지 않습니다. export를 하면 환경 변수가 되어 자식 프로세스에도 전해집니다. = 앞뒤에는 빈칸을 두지 않고, 값을 꺼낼 때는 $HOME처럼 이름 앞에 $를 붙입니다.

명령하는 일
env환경 변수만 늘어놓는다
set셸 변수까지 모두 늘어놓는다
export 이름=값변수를 환경 변수로 만든다
set(Windows 명령 프롬프트)환경 변수를 보고 정한다. 값은 %PATH%처럼 꺼낸다

2PATH — 명령을 찾는 차례

PATH는 명령을 찾을 디렉터리를 콜론(:)으로 이어 적은 환경 변수입니다(예: /usr/local/bin:/usr/bin:/bin). 명령 이름만 치면 셸은 PATH의 디렉터리를 앞에서부터 차례로 뒤져, 처음 찾은 실행 파일을 실행합니다. 같은 이름이 두 곳에 있으면 앞쪽 것이 실행되고, 끝까지 없으면 command not found를 알립니다.

디렉터리를 더할 때는 export PATH=$PATH:$HOME/bin⁠처럼 원래 값 뒤에 이어 붙입니다. 현재 디렉터리는 보통 PATH에 없어서, 여기 있는 스크립트는 ./sum.sh처럼 경로를 붙여 실행합니다.

3셸 스크립트 — 셸의 종류와 문법

스크립트의 첫 줄 #!/bin/bash는 어느 셸로 실행할지 적은 것입니다. 셸은 여럿이고, 시험에는 넷이 나옵니다.

셸가르는 특징
sh본 셸(Bourne shell). UNIX의 표준 셸로, bash·ksh의 바탕
bash본 어게인 셸(Bourne-Again shell). sh와 호환되고, 대부분의 Linux에서 기본 셸
cshC 셸(C shell). C 언어와 닮은 문법
ksh콘 셸(Korn shell). sh와 호환되며 csh의 기능을 더함

스크립트에 쓰는 기본 문법은 다섯입니다.

문법꼴뜻
변수n=1 · $n만들기 · 꺼내기
출력echo "n은 $n"화면에 한 줄 찍는다. 큰따옴표 안의 $n은 값으로 바뀐다
계산$((n + 1))식의 값. %는 나머지
조건if [ $n -eq 1 ] … fi-eq 같다 · -ne 다르다 · -gt 크다 · -lt 작다 · -ge 크거나 같다 · -le 작거나 같다
반복for n in 1 2 3 … done · while [ 조건 ] … done목록의 값을 하나씩 · 조건이 참인 동안

예제

먼저 그림의 변수 둘을 만들고, bash -c로 새 셸(자식 프로세스)을 띄워 두 변수를 찍게 합니다.

A=사과
export B=배
bash -c 'echo "A=$A, B=$B"'
A=, B=배

작은따옴표 안의 $A·$B는 처음 셸이 풀지 않고 자식 셸이 받아서 풉니다. export한 B만 자식 셸에 전해졌고, A는 처음 셸 안에만 있습니다.

다음은 sum.sh에 적어 chmod +x sum.sh로 실행 권한을 준 뒤 ./sum.sh로 실행한 스크립트입니다.

#!/bin/bash
sum=0
for n in 1 2 3 4
do
  if [ $((n % 2)) -eq 0 ]
  then
    sum=$((sum + n))
  fi
done
echo "합계: $sum"
합계: 6

n을 2로 나눈 나머지가 0인 짝수만 더합니다.

nn % 2sum
110
202
312
406

시험 포인트

  • 필기: env는 환경 변수만, set은 셸 변수까지 모두 보입니다. export는 셸 변수를 환경 변수로 만들어 자식 프로세스에 전합니다. Windows 명령 프롬프트에서 환경 변수를 보고 정하는 명령은 set입니다. PATH는 앞 디렉터리부터 뒤져 처음 찾은 것을 실행합니다. 셸 넷(sh·bash·csh·ksh)을 특징과 짝짓는 문제도 나옵니다.
  • 실기: 셸 스크립트의 출력을 줄바꿈까지 그대로 씁니다. 명령을 묻는 문제에는 env·set·export를 씁니다.

확인 문제

1. PATH가 /opt/tools:/usr/bin이고, 실행 파일 report가 /usr/bin과 /opt/tools 두 곳에 있습니다. report라고만 치면 일어나는 일로 알맞은 것을 고르세요.

  • ① /opt/tools/report가 실행됩니다.
  • ② /usr/bin/report가 실행됩니다.
  • ③ 두 파일이 차례로 실행됩니다.
  • ④ 이름이 겹쳐 command not found가 납니다.
정답

①입니다. 셸은 PATH에 적힌 차례대로 뒤지고, 처음 찾은 곳에서 멈춥니다. /opt/tools가 앞에 있습니다.

  • ② /usr/bin이 시스템 디렉터리라고 먼저 뒤지지 않습니다. 차례는 PATH에 적힌 대로입니다.
  • ③ 처음 찾은 파일 하나만 실행하고 뒤는 보지 않습니다.
  • ④ 겹쳐도 오류가 아닙니다. command not found는 어디에서도 못 찾았을 때 납니다.

2. 셸에서 MODE=test를 친 뒤 ./run.sh를 실행했더니, run.sh 안의 echo $MODE가 빈 줄을 찍었습니다. 까닭으로 알맞은 것을 고르세요.

  • ① MODE는 셸 변수라 자식 프로세스인 run.sh에 전해지지 않았습니다.
  • ② = 앞뒤에 빈칸이 없어서 값이 들어가지 않았습니다.
  • ③ run.sh에 실행 권한이 없었습니다.
  • ④ PATH에 MODE가 없었습니다.
정답

①입니다. export MODE=test로 만들었어야 run.sh가 값을 받습니다.

  • ② 거꾸로입니다. = 앞뒤에 빈칸을 두면 셸이 MODE를 명령 이름으로 읽습니다.
  • ③ 실행 권한이 없으면 run.sh가 돌지 않아 echo가 찍히지도 않습니다.
  • ④ PATH는 명령을 찾을 디렉터리 목록입니다. 변수를 건네는 일과 상관없습니다.

3. 다음 일을 하는 명령을 쓰세요. 답을 끝까지 쓴 뒤 정답을 펼치세요.

  • (가) 이 셸이 실행하는 프로그램에 건너가는 변수만 이름=값으로 늘어놓습니다.
  • (나) 이 셸 안에서만 쓰려고 만든 변수까지 모두 늘어놓습니다.
  • (다) 셸 변수 DB_HOST를 이 셸이 실행하는 프로그램에서도 읽게 합니다.
정답

받는 답: (가) env · (나) set · (다) export DB_HOST

(가)의 실마리는 '실행하는 프로그램에 건너가는 변수만', (나)는 '셸 안에서만 쓰는 변수까지 모두', (다)는 '실행하는 프로그램에서도 읽게'입니다.

  • 틀리는 꼴 set — (가)에: 셸 변수까지 모두 늘어놓아 건너가지 않는 변수도 섞입니다.
  • 틀리는 꼴 env — (나)에: 환경 변수만 보입니다. export하지 않은 셸 변수는 빠집니다.
  • 틀리는 꼴 set DB_HOST — (다)에: Linux 셸의 set은 변수를 건네지 않습니다. Windows의 set과 헷갈린 꼴입니다.

4. 예제 sum.sh의 조건을 -ne 0으로 바꿨습니다. 출력을 그대로 쓰세요. 답을 끝까지 쓴 뒤 정답을 펼치세요.

#!/bin/bash
sum=0
for n in 1 2 3 4
do
  if [ $((n % 2)) -ne 0 ]
  then
    sum=$((sum + n))
  fi
done
echo "합계: $sum"
정답

받는 답: 합계: 4

-ne는 '다르다'라서, 나머지가 0이 아닌 홀수 1과 3만 더합니다.

  • 틀리는 꼴 합계: 6: -ne를 -eq처럼 읽은 꼴입니다.
  • 틀리는 꼴 합계: 10: 조건을 건너뛰고 넷을 다 더한 꼴입니다.

5. 다음 스크립트의 출력을 그대로 쓰세요. 답을 끝까지 쓴 뒤 정답을 펼치세요.

#!/bin/bash
i=1
while [ $i -le 3 ]
do
  echo "회차 $i"
  i=$((i + 1))
done
echo "끝 $i"
정답

받는 답:

회차 1
회차 2
회차 3
끝 4

-le는 '작거나 같다'라서 i가 1·2·3일 때 세 번 돕니다. 세 번째에 i가 4가 되면 조건이 거짓이 되어 반복을 나오고, 마지막 줄이 4를 찍습니다.

  • 틀리는 꼴 끝 3: 반복을 나올 때 i가 이미 4로 늘어난 것을 놓친 꼴입니다.
  • 틀리는 꼴 회차 1~회차 2까지만: -le를 -lt(작다)로 읽은 꼴입니다.

끝까지 내려오면 저절로 표시됩니다. 이 기기에만 저장합니다.

정보처리기사 목차로