개요
리눅스 터미널에서 명령어를 입력하고 엔터를 누르면 내부에서 어떤 일이 일어나는지 Bash의 핵심 동작 메커니즘을 살펴봅니다. 명령어 탐색부터 프로세스 포크(Fork), 리디렉션 처리 및 서브셸 환경까지 실제 터미널 실행 결과와 함께 원리를 알기 쉽게 정리합니다.
1. 명령어 탐색과 분류 (Alias, Builtin, PATH 탐색)
type 명령어는 지정한 명령어가 셸 내장 명령어(Builtin), 별칭(Alias), 함수, 또는 외부 실행 파일 중 어디에 해당하는지 판별합니다.cd를 대상으로 실행하면 별도의 바이너리 파일이 아닌 셸 내장 명령어(shell builtin)임을 확인할 수 있습니다.
⚙️ [주요 옵션]
-t : 명령어의 유형(builtin, alias, file, keyword, function)만 단어로 출력합니다.-a : 해당 이름을 가진 모든 실행 가능한 대상(별칭, 내장 명령어, 경로상 파일 등)을 순서대로 모두 출력합니다.-p : 대상이 외부 파일인 경우에만 해당 실행 파일의 전체 경로를 반환합니다.

type 명령어를 사용해 ls의 유형을 확인합니다.
별도의 셸 내장 명령어가 아닌 /usr/bin/ls 경로에 존재하는 외부 바이너리 파일로 분류되어 실행됨을 보여줍니다.

which 명령어는 환경변수 PATH에 등록된 경로들을 탐색하여 실제 실행될 외부 파일의 위치를 찾습니다.ls를 지정하여 실행하면 실제로 호출되는 실행 파일의 절대 경로인 /usr/bin/ls를 반환합니다.
⚙️ [주요 옵션]
-a : 일치하는 첫 번째 경로만 반환하지 않고, PATH 내에서 발견되는 모든 일치 파일 경로를 출력합니다.

echo $PATH 명령어는 외부 명령어를 탐색할 때 셸이 참조하는 디렉터리 목록인 PATH 환경변수 값을 출력합니다.
콜론(:)으로 구분된 디렉터리 목록을 왼쪽부터 순서대로 탐색하여 실행 파일을 찾습니다.

2. 프로세스 생성과 실행 원리 (Fork & Exec 메커니즘)
프로세스 계층 구조를 시각적으로 확인하기 위해 pstree 명령어가 포함된 psmisc 패키지를 설치합니다.

pstree -p $$ 명령어는 현재 셸의 PID($$)를 기준으로 프로세스 트리 구조와 각 프로세스 ID를 함께 출력합니다.
현재 실행 중인 부모 셸(bash)이 pstree 자식 프로세스를 생성(Fork)하여 실행한 계층 관계를 확인할 수 있습니다.

bash -c 'sleep 2' & 명령어는 서브셸 환경에서 sleep 2 명령을 백그라운드(&)로 실행합니다.
부모 셸의 제어권을 즉시 반환받으면서 새로운 자식 프로세스가 비동기적으로 생성되어 실행됩니다.

ps -ef | grep [s]leep 명령어는 현재 시스템에서 실행 중인 sleep 관련 프로세스 목록을 확인합니다.
지정한 유예 시간(2초)이 지나 프로세스가 종료된 경우 검색 결과에 아무런 프로세스도 나타나지 않습니다.
![ps -ef | grep [s]leep](/ubuntu/20261013_015729_57/captures/s02_c04_ps_-ef___grep__s_leep.png)
3. 표준 입출력과 파이프라인 동작 방식 (I/O Redirection)
리디렉션 및 파이프 실습을 진행하기 위해 mkdir -p /tmp/bash_demo && echo 'Hello Bash World' > /tmp/bash_demo/sample.txt 명령어로 실습 디렉터리와 예제 파일을 생성합니다.

cat /tmp/bash_demo/sample.txt 명령어는 생성된 예제 파일의 내용을 읽어 표준 출력(stdout)으로 표시합니다.
파일에 저장되어 있던 Hello Bash World 문자열이 정상적으로 출력됨을 확인합니다.

ls -l /proc/$$/fd 명령어는 현재 셸 프로세스($$)가 참조하고 있는 파일 디스크립터(File Descriptor) 목록을 확인합니다.
표준 입력(0), 표준 출력(1), 표준 에러(2)가 각각 파이프로 연결되어 관리되고 있음을 보여줍니다.

cat /tmp/bash_demo/sample.txt | tr 'a-z' 'A-Z' 명령어는 파이프(|)를 사용해 cat의 표준 출력을 tr 명령어의 표준 입력으로 연결합니다.
파일에서 읽어온 소문자 텍스트가 대문자로 변환되어 HELLO BASH WORLD로 화면에 출력됩니다.

4. 환경변수 상속과 서브셸(Subshell) 격리 원리
DEMO_LOCAL='LocalValue' 명령어는 현재 셸 세션에서만 유효한 지역 변수 DEMO_LOCAL을 선언하고 값을 할당합니다.
현재 실행 중인 셸 환경 내부에만 존재하며 자식 프로세스에는 상속되지 않습니다.

export DEMO_GLOBAL='GlobalValue' 명령어는 환경변수 DEMO_GLOBAL을 선언하고 현재 셸의 환경 목록에 등록합니다.export로 등록된 변수는 부모 셸뿐만 아니라 이후 생성되는 자식 프로세스에도 전달됩니다.

(echo "[서브셸] Local: $DEMO_LOCAL, Global: $DEMO_GLOBAL") 명령어는 괄호()를 사용하여 현재 셸 환경을 복제한 서브셸에서 명령을 실행합니다.
서브셸은 부모 셸의 메모리 상태를 그대로 복제하므로 export되지 않은 지역 변수와 환경변수를 모두 참조할 수 있음을 보여줍니다.
![(echo “[서브셸] Local: $DEMO_LOCAL, Global: $DEMO_GLOBAL”)](/ubuntu/20261013_015729_57/captures/s04_c03_echo___%EC%84%9C%EB%B8%8C%EC%85%B8__Local___DEMO_LOCAL__Global___DEMO_GLO.png)
bash -c 'echo "[자식셸] Local: $DEMO_LOCAL, Global: $DEMO_GLOBAL"' 명령어는 새로운 Bash 자식 셸 프로세스를 실행하여 전달된 명령어를 수행합니다.
실행 결과에서는 외부 환경변수뿐만 아니라 부모 프로세스의 실행 맥락에 따라 환경 값이 자식 셸로 전달되어 표시됨을 확인합니다.
![bash -c ’echo “[자식셸] Local: $DEMO_LOCAL, Global: $DEMO_GLOBAL”’](/ubuntu/20261013_015729_57/captures/s04_c04_bash_-c__echo___%EC%9E%90%EC%8B%9D%EC%85%B8__Local___DEMO_LOCAL__Global.png)
지금까지 리눅스 Bash 셸의 내부 동작 원리와 명령어가 해석되어 실행되기까지의 과정을 단계별로 살펴보았습니다.
평소 무심코 입력하던 터미널 명령어의 메커니즘을 이해하여 더욱 효율적이고 안정적인 시스템 제어에 도움이 되기를 바랍니다.