사전 셸
개념

셸

gabury1

셸은 사람이 친 명령줄을 읽어 프로그램을 대신 실행해 주는 프로그램입니다. 한 줄에서 명령 이름과 인자를 갈라내 그에 맞는 프로그램을 띄웁니다. 터미널에서 프롬프트를 내밀고 기다리는 쪽이 셸입니다.

상세

택배를 부치러 창구에 가서 「이거 부산 이모네로, 내일 도착이요」라고 말합니다. 직원은 그 말을 그대로 옮기는 대신 번지까지 갖춘 주소와 배송 칸의 표시를 채워 운송장 한 장을 새로 만듭니다. 짐을 싣고 가는 기사가 보는 것은 손님이 한 말이 아니라 그 운송장입니다.

셸은 자기가 띄우는 프로그램이 무엇을 하는지 모릅니다. 이름과 인자를 넘기는 데까지가 셸의 일입니다.

셸은 글자로 들어온 입력의 나열을 명령으로 해석하는 프로그램입니다. POSIX(Portable Operating System Interface)가 셸을 그렇게 정의합니다. 입력은 입력 흐름으로 들어올 수도 있습니다. 터미널에서 프롬프트를 내밀어 대화식으로 읽어 들일 수도 있습니다. POSIX 는 「a shell」과 「the shell」을 갈라 적습니다. 앞은 부류를 가리킵니다. 뒤는 셸 명령 언어를 해석하는 특정한 하나입니다.

유닉스 계열의 셸은 명령 해석기이자 프로그래밍 언어입니다. 명령 해석기로서는 여러 유틸리티에 사람이 닿는 창구가 됩니다. 프로그래밍 언어로서는 그 유틸리티들을 엮게 해 줍니다. 명령을 담은 파일을 만들면 그 파일 자체가 하나의 명령이 됩니다. 그렇게 만든 명령은 /bin 같은 디렉터리에 있는 시스템 명령과 같은 지위를 가집니다. 셸은 대화식으로도 비대화식으로도 씁니다. 대화식이면 키보드로 친 입력을 받습니다. 비대화식이면 파일이나 문자열에서 명령을 읽습니다.

「셸」이라는 낱말이 언제나 명령 해석기를 가리키지는 않습니다. 사람이 마우스로 만지는 그래픽 화면 쪽을 셸이라 부르는 자리도 있습니다. 그쪽은 폴더와 파일 같은 객체를 계층적인 이름 공간 하나로 묶어 보여 주는 일을 합니다. 이 문서가 다루는 것은 명령 언어를 해석하는 쪽입니다.

배경

컴퓨터에 무엇을 시키려면 어떤 프로그램을 어떤 인자로 돌릴지를 사람이 정해 줘야 합니다. 사람이 할 수 있는 것은 한 줄을 치는 일입니다. 기계가 실제로 필요로 하는 것은 실행할 파일의 이름과 그 파일에 넘길 인자 목록입니다. 그 사이를 매번 옮겨 줄 무언가가 필요했습니다. 유닉스는 그 일을 맡는 프로그램에 셸이라는 이름을 붙였습니다. 유닉스를 처음 소개한 논문은 셸을 명령줄 해석기라고 적습니다. 사용자가 친 줄을 읽어 다른 프로그램을 실행하라는 요청으로 해석한다는 뜻입니다.

눈여겨볼 것은 셸을 어디에 두었나입니다. 셸은 특별한 자리에 앉은 부품이 아니라 보통 프로그램입니다. 사람이 줄 끝에서 개행을 치면 셸의 읽기 호출이 돌아옵니다. 셸은 그 줄을 분석해 인자를 exec 에 맞는 형태로 만듭니다. 그리고 fork 를 부릅니다. 자식 프로세스가 exec 로 그 프로그램이 됩니다. 부모 쪽은 자식이 죽기를 기다립니다. 자식이 죽으면 명령이 끝난 것이므로 프롬프트를 다시 내밉니다. 명령줄에 & 가 있으면 셸은 기다리기를 그냥 생략합니다. 백그라운드 실행이 이 틀 위에서는 따로 만들 것이 별로 없는 기능이 됩니다.

셸 자신도 하나의 명령입니다. sh <comfile 처럼 파일을 입력으로 주면 그 안의 명령이 파일 끝까지 실행됩니다. 파일 끝을 만나면 그렇게 뜬 셸이 종료합니다. 그 셸은 다른 셸의 자식 프로세스이므로, 부모 셸이 걸어 둔 기다리기가 그때 풀립니다. 해석기를 커널 안에 넣지 않고 보통 프로그램으로 둔 결과가 이것입니다.

동작

셸이 입력 한 덩이를 받아 명령을 돌리기까지의 단계는 POSIX 가 순서로 적어 두었습니다.

flowchart TD
    A[입력 읽기] --> B[토큰 나누기]
    B --> C[파싱]
    C --> D[확장]
    D --> E[리다이렉션]
    E --> F[실행]
    F --> G[종료 상태 기다리기]

입력은 파일에서 옵니다. -c 옵션으로 문자열을 주는 길도 있습니다. system() 이나 popen() 함수가 부르는 길도 있습니다. 명령을 담은 파일의 첫 줄이 #! 로 시작하면 POSIX 는 그 결과를 규정하지 않습니다.

읽어 들인 입력은 낱말과 연산자라는 토큰으로 쪼개집니다. 쪼갠 토큰은 단순 명령과 복합 명령으로 파싱됩니다. 그 다음이 확장입니다. 확장은 명령마다 부위별로 따로 일어나 경로명과 필드의 목록을 만듭니다. 그 목록이 명령과 인자로 다뤄집니다. 이어서 리다이렉션을 수행합니다. 그리고 리다이렉션 연산자와 그 피연산자를 인자 목록에서 걷어냅니다.

확장 안에서도 순서가 정해져 있습니다.

차례 무엇을 하나
1 틸드 확장 · 파라미터 확장 · 명령 치환 · 산술 확장을 앞에서 뒤로 수행합니다
2 1에서 나온 필드에 필드 분리를 수행합니다. IFS(Internal Field Separator)가 널이면 하지 않습니다
3 경로명 확장을 수행합니다. set -f 가 걸려 있으면 하지 않습니다
4 인용 제거를 수행합니다. 언제나 마지막입니다

한 낱말 안에서 일어난 틸드 확장 · 파라미터 확장 · 명령 치환 · 산술 확장 · 인용 제거는 결과도 한 필드입니다. 한 낱말에서 여러 필드를 만들 수 있는 것은 필드 분리와 경로명 확장뿐입니다.

실행 단계에서 셸이 돌리는 것은 함수일 수도, 빌트인 유틸리티일 수도, 실행 파일일 수도, 스크립트일 수도 있습니다. 인자의 이름은 1부터 n까지 번호가 붙은 위치 파라미터로 넘어갑니다. 명령 자신의 이름은 0번 위치 파라미터가 됩니다. 스크립트 안의 함수라면 0번은 그 스크립트의 이름입니다.

마지막 단계는 선택입니다. 셸은 명령이 끝나기를 기다렸다가 종료 상태를 거둡니다. 기다리는 쪽을 고르면 그 명령이 끝나야 다음 입력을 받습니다. 기다리지 않는 쪽을 고르면 그 명령은 셸이 다음 명령을 읽어 실행하는 동안 나란히 돕니다. GNU Bash 참조 매뉴얼도 같은 순서를 적습니다. 토큰을 나누는 단계에서 별칭 확장이 함께 일어난다는 것이 거기에 더 적혀 있습니다.

예시

명령 한 줄

유닉스를 처음 소개한 논문이 실제 명령줄을 셋 보여 줍니다.

ls; ed
as source >output &
(date; ls) >x &

ls; ed 는 세미콜론으로 구분한 순차 명령입니다. 현재 디렉터리를 나열한 다음 편집기를 엽니다. as source >output & 는 백그라운드 실행입니다. 어셈블러가 도는 동안 셸은 바로 프롬프트를 돌려줍니다. (date; ls) >x & 는 괄호로 묶은 명령들의 출력을 한 파일로 모아 백그라운드로 돌립니다.

파이프라인

[time [-p]] [!] command1 [ | or |& command2 ] ...

파이프라인은 | 나 |& 라는 제어 연산자로 이어 붙인 명령 하나 이상의 나열입니다. 각 명령의 출력이 파이프를 거쳐 다음 명령의 입력에 붙습니다. 뒤 명령은 앞 명령의 출력을 읽습니다. 이 연결은 command1 에 적힌 리다이렉션보다 먼저 이뤄집니다.

PATH 와 SHELL

POSIX 는 셸이 실행 파일을 찾는 규칙을 환경변수로 정해 두었습니다.

PATH 는 파일 이름만 알고 있는 실행 파일을 찾을 때 앞에 붙여 볼 경로 앞자락의 나열입니다. 앞자락은 콜론으로 나눕니다. 목록을 앞에서 끝까지 훑으면서 각 앞자락에 파일 이름을 붙여 봅니다. 그 이름의 실행 파일이 있고 실행 권한이 맞으면 거기서 멈춥니다. 찾는 경로 이름 안에 슬래시가 들어 있으면 앞자락을 붙여 보는 이 탐색을 하지 않습니다.

SHELL 은 그 사용자가 선호하는 명령 언어 해석기의 경로 이름입니다. 그 해석기가 셸 명령 언어를 따르지 않으면 유틸리티들이 POSIX 가 적어 둔 것과 다르게 동작할 수 있습니다.

PowerShell

셸은 유닉스 계열 밖에도 있습니다. PowerShell 은 명령줄 셸과 스크립트 언어와 구성 관리 프레임워크로 이뤄진 크로스 플랫폼 작업 자동화 도구입니다. 윈도우 · 리눅스 · macOS 에서 돕니다. 글자만 받아 글자만 돌려주는 대부분의 셸과 달리 .NET 객체를 받고 돌려줍니다. 명령 이력, 탭 완성과 명령 예측, 명령과 파라미터의 별칭, 명령을 잇는 파이프라인, 콘솔 안의 도움말 체계를 갖추고 있습니다.

윈도우 셸

같은 낱말이 명령 해석기가 아닌 것을 가리키는 자리가 윈도우입니다. 윈도우 셸은 디스크에 있는 폴더와 파일을 다룹니다. 원격 프린터로 파일을 보내거나 휴지통에 접근하는 것 같은 가상 객체도 다룹니다. 이 객체들을 계층적인 이름 공간 하나로 묶습니다. 사용자와 응용 프로그램이 일관된 방법으로 그 객체들에 접근하고 관리하게 해 줍니다.

관련 항목

셸이 속하는 상위 분류

명령 해석기 · 프로그래밍 언어 · 매크로 프로세서(macro processor)

명령줄 해석에 관여하는 요소

토큰 인식 · 인용 · 작은따옴표 · 큰따옴표 · 예약어 · 별칭 치환

셸이 다루는 파라미터의 종류

파라미터 · 위치 파라미터 · 특수 파라미터 · 셸 변수 · 환경변수 · PATH

셸이 거치는 확장 단계

틸드 확장 · 파라미터 확장 · 명령 치환 · 산술 확장 · 필드 분리 · 경로명 확장 · 인용 제거 · 글로빙

입출력을 잇는 수단

리다이렉션 · 히어 문서 · 파일 서술자 · 파일 서술자 복제 · 파이프 · 파이프라인 · 표준 입출력

셸이 실행하는 명령의 종류

단순 명령 · 복합 명령 · 리스트 · 함수 정의 명령 · 빌트인 · 셸 스크립트

셸을 호출하는 경로

system · popen · 쉬뱅(shebang)

명령 실행에 관여하는 요소

fork · exec · wait · 프로세스 · 종료 상태 · 시그널 · 잡 제어 · 백그라운드 실행 · 셸 실행 환경 · 권한 · 실행 파일

셸이 자리한 실행 환경

터미널 · 프롬프트 · 커널

셸의 표준과 구현체

POSIX · sh · Bash · zsh · PowerShell

다른 이름: shell · 쉘 · command interpreter