셸의 실행 원리: 인용·환경·파이프·종료 상태·tar
입력한 문자열이 인수와 프로세스로 바뀌는 과정부터 환경 상속, 입출력 연결, 스크립트와 아카이브의 동작을 추적한다.
개념부터 찾아보기
정의·역할·동작 원리를 독립 페이지에서 확인하세요. 본문의 밑줄 용어에도 설명이 있습니다.
이 노트에서 설명할 수 있게 되는 것
- 셸과 터미널·콘솔을 구분하고 인용이 인수에 미치는 영향을 설명한다.
- 표준 입출력과 파이프·종료 상태를 연결한다.
- 환경 상속과 스크립트 실행 방식, tar 생성·조회·추출의 차이를 적용한다.
01터미널·TTY·셸·프로세스의 관계
- 터미널터미널 에뮬레이터는 문자 입출력 화면과 키보드 입력을 제공하고, 셸은 그 안에서 명령을 해석하는 프로세스다.
- 콘솔콘솔은 직접 관리에 쓰는 입출력 통로를 가리키며 물리·가상·직렬 콘솔이 있다.
- 대화형·터미널SSH의 대화형 세션이나 터미널은 가상 터미널 장치인 PTS를 사용할 수 있다.
- Bash 실행 파일/bin/bash는 콘솔의 이름이 아니라 Bash 실행 파일 경로다.
- 셸의 명령 처리사용자가 명령을 입력하면 셸은 문법을 해석하고 확장·입출력 연결을 처리한 뒤 내장 기능 또는 외부 프로그램을 실행한다.
- 셸·종료 상태외부 명령이 끝나면 셸은 종료 상태를 받는다.
- Cd가 내장 명령인 이유cd는 현재 셸의 작업 디렉터리를 바꿔야 하므로 일반적인 사용에서는 셸 내장 명령으로 동작한다.
- 자식 자식 에서만 디렉터리를 바꾸면 부모 셸의 위치는 바뀌지 않는다.
- 명령 구문 해석셸이 입력을 단어·연산자 등으로 해석하여 단순 명령이나 파이프 등의 구조를 구분한다. 따옴표는 데이터의 경계와 이후 확장 방식을 정한다.
- 확장으로 인수 준비변수·명령 치환 등 해당 문맥에서 허용되는 확장을 처리한다. 인용하지 않은 확장 결과에는 ·경로명 확장이 추가로 적용될 수 있다.
- 입출력 연결 준비과 파이프가 지정됐으면 파일 디스크립터의 연결을 준비한다. 을 열지 못하는 등 이 단계의 오류로 명령 실행이 실패할 수 있다.
- 명령 실행현재 문맥에 따라 내장 명령이나 외부 프로그램을 실행한다. 외부 프로그램은 준비된 인수·환경과 연결된 표준 입출력을 전달받는다.
- 종료 상태 반영명령이 종료되면 셸은 상태를 받아 다음 조건식이나 후속 명령에 반영한다. 종료 상태와 표준 출력에 쓰인 데이터는 서로 다른 결과다.
printf "%s\n" "$SHELL"
ps -p $$ -o pid=,ppid=,comm=,args=
tty
type -a cd
command -v bash$SHELL은 로그인 셸 정보일 수 있다. 현재 셸 와 터미널 장치를 별도로 조회하는 예시. 출력 전체에 비밀값을 포함시키는 환경 조회는 생략했다.
02문자열을 인수로 나누는 인용과 확장
- 셸셸이 해석하는 따옴표는 프로그램에 전달할 데이터의 경계를 정한다.
- 는 내부 문자를 그대로 보존하고, 큰따옴표는 변수·명령 치환을 허용하면서 확장된 값이 공백으로 다시 나뉘거나 파일 이름 패턴으로 확장되는 것을 막는 데 사용한다.
- ·경로명 확장인용 없는 변수 확장은 와 경로명 확장의 영향을 받을 수 있으므로 파일 경로 같은 하나의 값을 전달할 때는 보통 큰따옴표로 감싼다.
- 인용에 따른 인수 수아래에서 첫 출력은 하나의 인수이고 두 번째는 공백으로 분리된 두 인수다.
- 세 번째는 변수의 값이 아니라 문자 $name을 출력한다.
- printf의 형식 문자열printf의 형식 문자열은 고정하고 데이터를 별도 인수로 주면 데이터 안의 % 문자를 형식 지시자로 해석하는 혼동도 피할 수 있다.
- 터미널프로그램이 실제로 받은 인수와 터미널에 보이는 명령 문자열은 같은 것이 아니다.
name="alpha beta"
printf "<%s>\n" "$name"
# <alpha beta>
printf "<%s>\n" $name
# <alpha>
# <beta>
printf "%s\n" '$name'
# $name본문의 조건을 가정한 교육용 예시.
PATH 설정을 쓸 때와 source할 때의 변수 확장 비교하기
따옴표와 실행 시점이 설정 파일에 저장되는 문자열 및 현재 셸 환경을 어떻게 바꾸는지 추적한다.
실습 구성과 전제
- 두 사진은 Miniconda 실행 경로를 셸 설정에 넣는 서로 다른 방법의 사례다. 운영용 /etc/bashrc를 그대로 수정하지 않고 새 실습 디렉터리의 파일로 재구성한다.
- Bash의 큰따옴표와 를 비교한다. 실제 Miniconda 설치 경로는 환경마다 다르며 추가가 환경 활성화와 같은 작업은 아니다.
큰따옴표 안의 변수는 설정을 쓰는 순간 확장된다
- 첫 사진은 echo의 큰따옴표 안에서 $를 사용하고 결과를 파일에 추가한다. 현재 셸이 변수 값을 먼저 넣으므로 저장되는 문자열에는 그 시점의 값이 포함된다.
- 이 방식은 다른 계정·세션에서도 재평가할 식을 남기려는 의도와 다를 수 있다. 사진의 성공 여부와 별개로 파일에 실제 어떤 문자열이 쓰였는지 읽어야 한다.
원본 크기로 보기 ↗- echo 명령의 export PATH 표현이 큰따옴표로 감싸져 있다.
- 출력은 >>로 /etc/bashrc에 추가되며 Miniconda의 bin 경로가 포함되어 있다.
확인 기준파일에 $라는 글자가 남았는지 이미 긴 경로 목록으로 바뀌었는지 구분한다. 따옴표 종류가 단순한 꾸밈이 아니다.
작은따옴표로 식을 보존하고 실행 시점을 늦춘다
- 두 번째 사진의 안에서는 셸이 $를 즉시 치환하지 않는다. sed가 추가한 설정 행을 나중에 셸이 읽을 때 변수 확장이 일어난다.
- 재구성 예시는 새 파일에 식을 저장한 뒤 cat으로 확인한다. printf에 전달한 는 제거되지만 그 안의 $HOME·$ 문자열은 파일에 그대로 남는다.
bashprintf '%s\n' 'export PATH="$HOME/miniconda3/bin:$PATH"' > ./lab-env.sh cat ./lab-env.sh새 빈 실습 디렉터리에서만 사용할 파일 작성 예시다. 시스템 설정 파일을 변경하지 않는다.
원본 크기로 보기 ↗- sed에 전달하는 추가 스크립트가 작은따옴표로 묶여 있고 $PATH가 포함되어 있다.
- 그 뒤 source, PATH 조회, conda 관련 명령이 이어져 파일 작성과 환경 적용이 별도 단계임을 보여 준다.
확인 기준설정 파일 내용에 변수를 남기는 것과 현재 셸에서 그 변수를 확장하는 것은 다른 시점의 작업이다.
source의 영향 범위를 자식 셸로 제한해 확인한다
- source는 현재 셸 안에서 파일의 문장을 실행한다. 반면 별도로 실행한 bash 의 환경 변경은 부모 셸로 거슬러 올라가지 않는다.
- 아래 예시는 자식 Bash에서만 파일을 source한 뒤 경로와 명령 위치를 확인한다. 명령 발견이나 버전 출력은 환경이 활성화되었다는 증거와는 다르다.
bashbash -c 'source ./lab-env.sh; printf "%s\n" "$PATH"; command -v conda; command -v python' command -v python첫 행의 환경 변경은 자식 Bash에만 적용된다. 다음 행은 원래 셸의 명령 탐색 결과다.
확인 기준명령 위치가 기대한 설치 경로인지 확인한다. 에서 찾은 실행 파일과 의 활성 환경· sys.executable을 혼동하지 않는다.
실습에서 확인한 동작 원리
- 따옴표는 변수 확장 여부를 정하고, 파일 작성과 source는 서로 다른 확장 시점을 만든다.
- 환경은 부모에서 자식으로 전달되며 자식에서 바꾼 가 부모 셸을 자동 변경하지 않는다.
설정·출력 추가로 확인하기 1장
아래 화면을 펼쳐 위 실습의 설정값, 명령과 확인 기준을 비교해 보세요. 각 묶음은 별도 실습 기록입니다.
실습 화면 묶음 01 1장
원본 크기로 보기 ↗- 문서 문맥에 삽입된 원본 실습·개념 참고 화면이다. 셸의 실행 원리 학습 내용과 함께 당시 구성·설정·관찰 결과를 비교할 수 있다.
동작·명령 참고 문서
03셸 변수·export·자식 프로세스 환경
- 셸변수 대입은 현재 셸 안의 값을 만든다.
- 로 표시한 변수는 이후 실행하는 자식 의 환경에 포함된다.
- 자식자식이 환경 값을 바꾸어도 부모의 값이 자동으로 바뀌지 않으며, 이미 실행 중인 다른 에도 변경이 전달되지 않는다.
- 명령별 임시 환경명령 앞의 NAME=value는 그 명령의 실행 환경에 값을 제공하는 형태로 사용한다.
- 는 명령 이름에 슬래시가 없을 때 실행 파일을 찾는 디렉터리 목록이며 앞에서부터 검색한다.
- 우선순위앞쪽에 쓰기 가능한 디렉터리나 현재 디렉터리를 두면 의도하지 않은 같은 이름의 파일을 실행할 수 있다.
- 별칭·함수·내장 명령도 해석에 관여하므로 type -a와 command -v로 무엇이 선택되는지 확인한다.
STUDY_MODE=local
export STUDY_MODE
bash -c 'printf "%s\n" "$STUDY_MODE"'
# local
STUDY_MODE=child bash -c 'printf "%s\n" "$STUDY_MODE"'
# child
printf "%s\n" "$STUDY_MODE"
# local본문의 조건을 가정한 교육용 예시.
04로그인·대화형·서비스 환경의 차이
- 로그인 셸Bash 로그인 셸은 /etc/profile과 사용자 시작 파일을 읽으며, 사용자 파일은 ~/.bash_profile, ~/.bash_login, ~/.profile 가운데 읽을 수 있는 첫 파일을 사용한다.
- 대화형·비로그인대화형 비로그인 Bash는 일반적으로 ~/.bashrc를 읽는다.
- 배포배포판의 시작 파일이 다른 파일을 다시 읽도록 구성될 수 있으므로 모든 파일이 무조건 읽힌다고 가정하지 않는다.
- 대화형·셸 시스템 서비스는 사용자의 대화형 셸에서 시작한 가 아니므로 그 사용자의 profile이나 를 자동으로 이어받지 않는다.
- EnvironmentUnit의 Environment와 EnvironmentFile 등 서비스가 실제로 읽는 위치에 필요한 값을 둔다.
- /etc/environment/etc/environment는 셸 스크립트가 아니므로 ·명령 치환·일반 셸 확장을 기대하지 않는다.
- 환경 파일환경 파일을 바꾼 뒤 새 가 어떤 값을 받는지가 적용 여부를 결정한다.
05파일 디스크립터와 리다이렉션 순서
- 표준 입력·파일 디스크립터표준 입력은 파일 디스크립터 0, 표준 출력은 1, 표준 오류는 2다.
- 은 이 번호가 가리키는 대상을 바꾼다.
- 파일 연결 연산자>는 기본적으로 을 새로 만들거나 기존 내용을 비우고, >>는 끝에 추가하며, <는 파일을 입력으로 연결한다.
- 셸셸이 파일을 여는 단계에서 실패하면 대상 명령이 실행되기 전에 실패할 수 있다.
- 표준 출력2>&1은 오류를 현재 표준 출력과 같은 대상으로 연결한다.
- 따라서 command >out.log 2>&1은 두 출력을 파일로 보내지만 command 2>&1 >out.log는 먼저 오류를 기존 출력 대상에 연결한 뒤 표준 출력만 파일로 바꾼다.
- 셸 문법과 명령 옵션명령 뒤에 쓴 기호를 프로그램의 자체 옵션으로 오해하지 않고 셸이 처리하는 연결로 읽는다.
- 기존 출력 대상command >out.log 2>&1을 예로 든다. 처음에 표준 출력 1과 표준 오류 2가 터미널에 연결돼 있다고 가정한다.
- 첫 적용>out.log가 파일을 열고 표준 출력 1을 그 파일에 연결한다. 기존 파일의 내용을 비울 수 있으므로 읽기 전용 동작이 아니다.
- 두 번째 연결 복제2>&1이 이 시점의 표준 출력 연결을 표준 오류에도 복제한다. 1과 2 모두 같은 로 향하게 된다.
- 명령의 출력 기록명령이 실행되면 표준 출력과 오류가 파일에 기록된다. 기호 순서를 2>&1 >out.log로 바꾸면 오류는 기존 터미널에 남는다.
| 표현 | 연결 결과 |
|---|---|
| command <input.txt | 파일 내용을 표준 입력으로 제공 |
| command >out.log | 표준 출력을 파일로 연결 |
| command 2>error.log | 표준 오류만 파일로 연결 |
| command >out.log 2>&1 | 두 출력을 같은 파일로 연결 |
06파이프와 종료 상태는 데이터와 별개다
- 파이프·표준 출력파이프는 앞 명령의 표준 출력을 뒤 명령의 표준 입력으로 연결한다.
- 파이프의 동시 처리두 명령이 순차적으로 모든 출력을 파일에 저장한 뒤 실행되는 구조가 아니라 동시에 데이터를 주고받을 수 있는 연결이다.
- 표준 오류는 따로 연결하지 않으면 파이프의 데이터가 아니다.
- 소비자 종료의 영향뒤 프로그램이 입력을 더 읽지 않고 종료하면 앞 프로그램의 쓰기가 실패할 수도 있다.
- 종료 상태종료 상태 0은 일반적으로 성공을 나타내고 0이 아닌 값은 도구별로 의미가 다르다.
- grep 종료 상태grep의 1은 일치 없음일 수 있어 실행 오류와 구분해야 한다.
- 파이프·종료 상태기본 파이프 종료 상태는 마지막 명령의 상태이고, Bash의 pipefail은 실패한 명령 중 가장 오른쪽의 상태를 반영한다.
- 파이프 전체의 성공 판정출력이 비어 있거나 마지막 명령이 성공한 것만으로 전체 단계가 성공했다고 판단하지 않는다.
printf "%s\n" beta alpha alpha | sort | uniq -c
# 2 alpha
# 1 beta
false | true
printf "%s\n" "$?"
# 기본 설정에서는 0
( set -o pipefail; false | true; printf "%s\n" "$?" )
# 1본문의 조건을 가정한 교육용 예시.
07파이프의 바이트 스트림·버퍼·EOF 조건
- 끝점 연결일반 파이프는 읽기 끝과 쓰기 끝을 가진 단방향 바이트 통로다. 셸은 앞 명령의 stdout을 쓰기 끝에, 뒤 명령의 stdin을 읽기 끝에 연결한다.
- 메시지 경계 없음한 번 write한 단위가 한 번 read할 단위와 같다고 보장하지 않는다. 여러 쓰기가 합쳐지거나 나뉘어 읽힐 수 있어 줄·길이·구분자 같은 상위 규칙으로 레코드를 해석한다.
- 버퍼의 역압blocking 모드에서 빈 파이프의 read는 자료를 기다리고 가득 찬 파이프의 write는 소비를 기다린다. 소비자가 느리면 생산자도 계속 무제한으로 출력할 수 없다.
- EOF의 조건버퍼의 남은 자료를 다 읽고 모든 쓰기 끝 참조가 닫혀야 읽기가 EOF를 볼 수 있다. 다른 자식이 불필요한 쓰기 FD를 잡고 있으면 생산자가 끝나도 소비자가 기다릴 수 있다.
- 읽는 쪽 종료모든 읽기 끝이 닫힌 뒤 쓰면 SIGPIPE가 발생할 수 있고, 신호를 무시하는 경우 EPIPE 오류를 받는다. 뒤 명령이 필요한 양만 읽고 종료한 상황과 원래 생산자 장애를 구분한다.
08세 명령의 종료 상태를 pipefail로 비교하기
- 가상 파이프아래 Bash 파이프에서 앞 두 서브셸은 각각 3과 7로 종료하고 마지막 true는 0으로 종료한다. 데이터를 생산하지 않는 상태 추적 예시다.
- 기본 판정pipefail을 끈 첫 실행의 전체 상태 $?는 마지막 명령의 0이다. 앞에서 두 명령이 실패 상태를 돌려도 전체 상태만 보면 성공처럼 보인다.
- 개별 상태PIPESTATUS에는 가장 최근 foreground 파이프 각 명령의 상태 3·7·0이 들어 있다. 다른 명령을 실행하기 전에 읽어야 그 파이프의 정보를 보존한다.
- pipefail 판정pipefail을 켠 둘째 실행은 0이 아닌 상태 중 가장 오른쪽인 7을 전체 상태로 사용한다. 실패 코드 중 최댓값을 고르는 규칙은 아니다.
- 해석의 범위pipefail은 상태 합성 규칙만 바꾼다. 이미 수행한 앞 단계의 작업을 되돌리거나 출력 데이터의 완전성을 검사하지는 않는다.
set +o pipefail
(exit 3) | (exit 7) | true
printf 'overall=%s statuses=%s\n' "$?" "${PIPESTATUS[*]}"
# 예상: overall=0 statuses=3 7 0
set -o pipefail
(exit 3) | (exit 7) | true
printf 'overall=%s statuses=%s\n' "$?" "${PIPESTATUS[*]}"
# 예상: overall=7 statuses=3 7 0실행하지 않은 Bash 전용 교육 예시. 명령 치환으로 실행한 결과가 아니며 printf 인수 확장은 해당 명령 실행 전에 이루어진다.
09인수 경계·서브셸·FD 누수를 나눠 진단하기
- 공백이 있는 인수Bash 배열 args=("alpha beta" "*.log")를 "${args[@]}"로 확장하면 두 인수의 경계를 유지한다. 문자열 하나로 합친 뒤 다시 인용 없이 확장하면 ·경로명 확장으로 의미가 달라질 수 있다.
- 파이프 속 변수Bash의 일반적인 파이프 구성에서는 각 명령이 서브셸 환경에서 실행되어 while read 안의 변수 변경이 바깥에 남지 않을 수 있다. lastpipe 같은 예외 설정을 포함해 실행 문맥을 확인한다.
- 상태 덮어쓰기실패 명령 다음에 echo나 logger를 실행하고 $?를 읽으면 그 후속 명령의 상태를 읽게 된다. 원래 상태가 필요한 분기에서 즉시 보존한다.
- 끝나지 않는 read생산자의 종료 시각만 보지 않고 파이프 쓰기 끝을 상속한 다른 자식이 남았는지 확인한다. EOF를 보내는 별도 문자가 있다고 생각하면 FD 수명 문제를 놓친다.
- 작은 출력과 큰 출력작은 자료는 통과하지만 큰 자료에서 멈추면 버퍼 용량과 읽기·쓰기 순서를 조사한다. 파이프 용량을 고정 상수로 가정하거나 소비 없이 무제한 누적하는 방식은 이식성과 안정성을 해친다.
10조건·반복·함수로 상태를 명시하기
- If의 분기 기준if는 뒤에 실행한 명령의 종료 상태에 따라 분기한다.
- 함수의 종료 상태함수도 명령처럼 실행되고 마지막 명령 또는 return의 값을 상태로 돌려준다.
- 출력과 종료 코드출력 값과 종료 상태는 서로 다른 통로이므로 결과 문자열을 성공 여부 대신 사용하지 않는다.
- IFS·read -r파일 경로를 줄 단위로 읽을 때는 공백과 역슬래시를 보존하도록 IFS= read -r 형태를 사용할 수 있다.
- set -eset -e는 모든 실패를 자동으로 안전하게 처리하는 장치가 아니다.
- 파이프조건식·논리 연산·파이프·함수의 문맥에 따라 동작이 달라질 수 있다.
- 명시적 실패 처리중요한 실패는 if/else에서 상태를 즉시 저장하고 성공·실패 경로를 명시한다.
- set -uset -u는 미정의 변수 사용을 검사하고 pipefail은 파이프 상태를 바꾸지만 입력 검증이나 ·원복을 대신하지 않는다.
for item in alpha beta; do
printf "item=%s\n" "$item"
done
if command -v tar >/dev/null 2>&1; then
printf "%s\n" "tar available"
else
printf "%s\n" "tar unavailable" >&2
fi본문의 조건을 가정한 교육용 예시.
11스크립트 실행·source·작업 제어
- shebang직접 실행하는 스크립트의 shebang은 인터프리터를 지정한다.
- #!/bin/bash는 고정 경로를 사용하고 #!/usr/bin/env bash는 실행 환경의 에서 Bash를 찾는다.
- sourcebash script.sh로 실행하면 지정한 Bash가 파일을 읽고, source 또는 점(.)으로 읽으면 현재 셸 안에서 처리하므로 변수와 디렉터리 변경이 현재 세션에 남을 수 있다.
- 서브셸괄호로 묶은 명령은 서브셸 환경에서 실행되어 내부 상태 변경을 분리할 수 있다.
- 백그라운드 실행뒤에 &를 붙이는 것은 비동기 실행이며 작업이 서비스로 등록되었다는 뜻은 아니다.
- 셸jobs·fg·bg는 셸의 작업 제어 기능이고, 장기 서비스의 재시작·로그·부팅 연동은 같은 서비스 관리의 범위다.
- 콘솔네트워크 변경으로 SSH가 끊길 때 복구할 콘솔 경로도 별도로 필요하다.
12tar는 묶음과 메타데이터를 만드는 도구다
- tartar는 파일·디렉터리·경로·일부 메타데이터를 하나의 로 묶는다.
- 은 별도 기능이며 -z는 gzip, -j는 bzip2, -J는 xz를 사용한다.
- 추출·는 생성, -t는 목록, -x는 추출이며 -f 뒤에는 경로가 온다.
- 는 뒤에 처리하는 상대 경로의 기준 디렉터리를 바꾼다.
- 아래 생성 예시는 준비한 실습 디렉터리와 새 출력 경로를 가정한다.
- 을 원본 디렉터리 안에 두면 자기 자신을 묶는 문제가 생길 수 있다.
- 추출목록 조회는 실제 추출과 구분하고 절대 경로·상위 이동·심볼릭 링크·민감 파일을 살펴본다.
- 은 파일 일치 확인에 쓰며 신뢰할 수 있는 출처의 값과 비교해야 의미가 있다.
tar -c -z -f /tmp/study-new.tar.gz -C /srv/study payload
tar -t -v -f /tmp/study-new.tar.gz/srv/study/payload가 준비되고 출력 경로가 새 파일인 실습 예시. 첫 줄은 를 생성하며 두 번째 줄은 내용 목록만 조회한다.
13추출과 배포·백업의 경계
- 격리된 추출 검증검토한 는 새 검증 디렉터리에 일반 사용자 권한으로 추출해 내용과 권한을 먼저 확인할 수 있다.
- 소유자·권한 복구 옵션의 --no-same-owner와 --no-same-permissions는 기록된 소유자·권한을 그대로 강제 복구하지 않기 위한 선택이며 적용되는 와 정책도 결과에 영향을 준다.
- 빈 디렉터리빈 디렉터리가 준비되지 않았으면 기존 서비스 경로를 대신 사용하는 식으로 진행하지 않는다.
- 추출·배포추출은 배포 완료가 아니다.
- 의존성, 설정, 서비스 계정, 건강 상태와 원복 경로를 따로 다룬다.
- DB 백업의 일관성실행 중인 DB 파일을 tar로 복사하는 것만으로 일관된 이 보장되지 않는다.
- 형식 save/load 도 일반 애플리케이션 파일 묶음과 형식·복원 절차가 다르다.
- 백업 대상의 상태무엇의 어떤 상태를 보관하는지 이해한 뒤 알맞은 방법을 선택한다.
tar -x -f /tmp/study-new.tar.gz -C /tmp/study-verify \
--no-same-owner --no-same-permissions원본·목록을 검토했고 /tmp/study-verify가 새 빈 검증 디렉터리로 준비된 추출 예시.
이해했는지 확인하기
- 입력과 전제 조건에서 정상 상태까지의 처리 순서를 설명한다.
- 조회 결과가 입증하는 범위와 아직 확인하지 않은 상태를 구분한다.
- 예제 설정의 대상·권한·환경을 실제 실습 조건에 맞게 정한다.