Computer >> 컴퓨터 >  >> 프로그래밍 >> Bash 프로그래밍

Bash의 $$와 $BASHPID 차이점 완벽 정리

최근 셸 스크립트를 작성하던 중 Bash 특수 변수인 $$$BASHPID가 서로 다르게 동작한다는 점을 발견했습니다. 리눅스에서 실행되는 모든 프로세스에는 프로세스 ID(PID)가 할당되며, 운영체제는 바로 이 ID를 통해 각 프로세스를 식별하고 관리합니다.

현재 셸의 프로세스 ID 확인하기

마찬가지로 Bash 터미널 세션에도 고유한 프로세스 ID가 부여됩니다. 현재 셸의 프로세스 ID를 저장하는 특수 변수로 "$$""$BASHPID"가 있는데요. 아래 명령어를 실행해 현재 셸의 프로세스 ID를 직접 확인해 보세요. 메인 셸에서는 두 변수 모두 동일한 값을 반환합니다.

$ echo $$               # 특수 변수 $$ 출력
$ echo $BASHPID         # 변수 $BASHPID 출력
Bash의 $$와 $BASHPID 차이점 완벽 정리

서브셸(자식 프로세스) 생성 과정 이해하기

Bash에서 셸로부터 외부 프로그램을 호출하면 자식 프로세스(서브셸)가 생성되고, 해당 프로그램은 오직 이 자식 프로세스 안에서만 실행됩니다. 아래 예시는 부모 셸이 프로그램을 실행하기 위해 서브셸을 생성하는 과정을 보여주기 위해, 간단한 프로세스 모니터링 명령어를 담은 "sample.sh"라는 스크립트입니다.

#!/usr/bin/env bash

ps -ef --forest | grep -i bash

이 스크립트를 실행하면 bash의 프로세스 구조를 확인할 수 있습니다. 아래 이미지를 보면 스크립트 호출 시 bash가 자식 프로세스를 생성하고, 그 안에서 스크립트를 실행하는 것을 알 수 있습니다.

$ ./sample.sh
Bash의 $$와 $BASHPID 차이점 완벽 정리

스크립트 내에서 $$와 $BASHPID 비교하기

이번에는 스크립트 안에서 "$$""$BASHPID"를 함께 출력해 어떤 값이 반환되는지 살펴보겠습니다.

#!/usr/bin/env bash
echo "============================"
ps -ef --forest | grep -i bash
echo "============================"
echo "PID USING $ FOR SCRIPT $0 ==> $$"
echo "PID USING BASHPID FOR SCRIPT $0 ==> $BASHPID"
echo

다시 스크립트를 실행합니다.

$ ./sample.sh
Bash의 $$와 $BASHPID 차이점 완벽 정리

결과적으로 두 변수 모두 동일한 프로세스 ID를 반환했습니다. 그렇다면 진짜 차이는 어디서 드러날까요? 괄호 () 안에 명령어를 넣어 스크립트 내부에 또 하나의 자식 프로세스를 만들어 보겠습니다.

괄호()로 서브셸을 만들 때 나타나는 차이

# PID를 변수에 저장...

VAR_HASH=$(echo $$)
VAR_BASHPID=$(echo $BASHPID)

echo "VALUE OF VAR_HASH ==> $VAR_HASH"
echo "VALUE OF VAR_BASHPID ==> $VAR_BASHPID"
Bash의 $$와 $BASHPID 차이점 완벽 정리

Bash에서 괄호(Parentheses)는 자식 프로세스를 호출하고 괄호 안의 내용을 실행합니다. 따라서 $$$BASHPID 모두 새로운 자식 프로세스 ID를 저장해야 할 것 같지만, 위 결과에서 뚜렷한 차이를 확인할 수 있습니다. $$는 부모 프로세스 ID, 즉 스크립트 sample.sh의 프로세스 ID인 382를 저장한 반면, $BASHPID는 괄호가 새로 생성한 자식 프로세스의 ID를 저장했습니다.

매뉴얼(man page)로 동작 원리 파악하기

이제 이 동작 방식이 왜 그런지 이해해 보겠습니다. Bash 매뉴얼 페이지에서 어떻게 설명하는지 확인해 보겠습니다.

$ man bash
Bash의 $$와 $BASHPID 차이점 완벽 정리 Bash의 $$와 $BASHPID 차이점 완벽 정리

정리하면 다음과 같습니다. $$를 사용하면 서브셸 안에서도 자신이 생성된 부모 프로세스의 ID를 가리킵니다. 반면 BASHPID는 항상 현재 프로세스의 ID를 저장합니다. 즉, 괄호 안에서 호출하면 자식 프로세스의 ID가 반환되는 것입니다.

변수 재할당과 unset 동작의 차이

$$ 변수는 값을 할당하거나 수정할 수 없습니다. 반면 BASHPID는 재할당 자체는 가능하지만 아무런 효과가 없습니다.

$ $=10
$ BASHPID=10
$ echo $BASHPID
Bash의 $$와 $BASHPID 차이점 완벽 정리

흥미로운 점은 BASHPID를 unset으로 해제할 수 있다는 것입니다. unset하면 특수 변수로서의 상태를 잃고, 이후에는 일반 변수처럼 자유롭게 사용할 수 있게 됩니다.

$ unset BASHPID
$ echo $BASHPID
$ BASHPID="Tecmint"
$ echo $BASHPID
Bash의 $$와 $BASHPID 차이점 완벽 정리

unset 이후에는 셸의 프로세스 ID를 다시 할당하더라도 이미 특수 상태를 잃었기 때문에 일반적인 사용자 정의 변수로 취급됩니다.

$ BASHPID=$(echo $$)
$ echo $$;echo $BASHPID
Bash의 $$와 $BASHPID 차이점 완벽 정리

이 경우 BASHPID의 특수 변수 기능을 되찾으려면 새로운 터미널 세션을 열어야 합니다.

마무리

지금까지 $$BASHPID의 차이점과 각각의 동작 방식을 예제와 함께 살펴보았습니다. 두 변수는 메인 셸에서는 같은 값을 반환하지만, 서브셸 환경에서는 전혀 다른 결과를 보인다는 점이 핵심입니다. 직접 실습해 보시고 소중한 피드백을 공유해 주시기 바랍니다.