pushd와 popd 명령어는 Bash 셸에 내장된 기능으로, 하드 드라이브상의 여러 위치를 빠르게 오갈 수 있도록 디렉터리를 '북마크'해 두는 역할을 합니다. 터미널은 컴퓨터를 탐색할 수 있는 놀랍도록 빠른 방법입니다. 몇 번의 키 입력만으로 하드 드라이브, 외장 저장소, 네트워크 공유 어디든 이동할 수 있으니까요. 하지만 특정 디렉터리 사이를 계속 왕복하거나 파일 시스템 속에서 길을 잃었을 때는 그 속도가 무용지물이 됩니다. 바로 이런 문제를 pushd와 popd가 해결해 줍니다.
pushd란?
가장 기본적인 수준에서 pushd는 cd와 매우 비슷합니다. 한 디렉터리에서 다른 디렉터리로 이동시켜 주죠. 예를 들어 one이라는 디렉터리 안에 two라는 하위 디렉터리가 있고, 그 안에 다시 three라는 하위 디렉터리가 있다고 가정해 봅시다. 현재 작업 디렉터리가 one이라면 cd 명령어로 two나 three, 어디든 이동할 수 있습니다.
$ pwd
one
$ cd two/three
$ pwd
three
pushd로도 같은 작업을 할 수 있습니다.
$ pwd
one
$ pushd two/three
~/one/two/three ~/one
$ pwd
three
결과만 보면 pushd와 cd는 동일하지만, 중간에 한 가지 추가 출력이 있습니다. pushd는 목적지 디렉터리와 출발점을 함께 표시합니다. 이것이 바로 디렉터리 스택(directory stack)이며, pushd를 독특하게 만드는 핵심 요소입니다.
스택(Stack)이란?
컴퓨터 용어에서 스택(stack)은 요소들의 모음을 의미합니다. 이 명령어의 맥락에서 요소란 pushd 명령어로 최근 방문한 디렉터리들입니다. 일종의 방문 기록 또는 빵 부스러기 흔적(breadcrumb trail)이라고 생각하면 이해하기 쉽습니다.
pushd로 파일 시스템 곳곳을 이동할 때마다 이전 위치와 새 위치가 스택에 차례로 추가됩니다.
$ pushd four
~/one/two/three/four ~/one/two/three ~/one
$ pushd five
~/one/two/three/four/five ~/one/two/three/four ~/one/two/three ~/one
스택 탐색하기
스택이 쌓이면 북마크나 빠른 이동 지점처럼 활용할 수 있습니다. 예를 들어 세션 내내 ~/one/two/three/four/five 디렉터리 구조에서 작업하고 있다고 가정해 봅시다. 최근에 one 디렉터리에 들렀다는 것은 기억나지만, 스택의 어느 위치에 있는지 정확히 기억나지 않을 수 있습니다. 이럴 때 +0(플러스 기호와 숫자 0) 인수를 사용하면 됩니다. 이 옵션은 스택의 어떤 디렉터리로도 이동하지 않으면서 현재 스택 전체를 화면에 출력해 줍니다.
$ pushd +0
~/one/two/three/four ~/one/two/three ~/one ~/one/two/three/four/five
또는 dirs 명령어로 스택을 확인할 수 있고, -v 옵션을 사용하면 각 디렉터리의 인덱스 번호까지 볼 수 있습니다.
$ dirs -v
0 ~/one/two/three/four
1 ~/one/two/three
2 ~/one
3 ~/one/two/three/four/five
스택의 첫 번째 항목은 현재 위치입니다. 평소처럼 pwd로 확인할 수 있습니다.
$ pwd
~/one/two/three/four
0(현재 위치이자 스택의 첫 번째 항목)부터 시작할 때, 스택의 두 번째 요소는 ~/one이며, 이것이 원하는 목적지입니다. +2 옵션을 사용하면 스택에서 앞으로 이동할 수 있습니다.
$ pushd +2
~/one ~/one/two/three/four/five ~/one/two/three/four ~/one/two/three
$ pwd
~/one
이렇게 하면 작업 디렉터리가 ~/one으로 변경되고, 동시에 스택이 재배열되어 새 위치가 맨 앞으로 옵니다.
스택에서 뒤로 이동할 수도 있습니다. 예를 들어 위 출력 상태에서 ~/one/two/three로 빠르게 이동하려면 한 칸 뒤로 이동하면 됩니다. 단, pushd는 0부터 시작한다는 점에 유의하세요.
$ pushd -0
~/one/two/three ~/one ~/one/two/three/four/five ~/one/two/three/four
스택에 디렉터리 추가하기
이런 식으로 스택을 계속 탐색할 수 있으며, 스택은 최근 방문한 디렉터리의 고정된 목록으로 유지됩니다. 새 디렉터리를 추가하려면 해당 경로를 입력하기만 하면 됩니다. 스택에 없던 새 디렉터리라면 예상대로 목록에 추가됩니다.
$ pushd /tmp
/tmp ~/one/two/three ~/one ~/one/two/three/four/five ~/one/two/three/four
하지만 이미 스택에 존재하는 디렉터리라면 중복되어 두 번 추가됩니다.
$ pushd ~/one
~/one /tmp ~/one/two/three ~/one ~/one/two/three/four/five ~/one/two/three/four
스택은 자주 접근하고 싶은 디렉터리 목록으로 쓰이기도 하지만, 실제로는 방문했던 곳의 진짜 기록(history)입니다. 디렉터리가 스택에 중복해서 추가되는 것을 원하지 않는다면 +N과 -N 표기법을 사용해야 합니다.
스택에서 디렉터리 제거하기
스택은 당연히 불변(immutable)하지 않습니다. pushd로 항목을 추가하거나 popd로 제거할 수 있습니다.
예를 들어 방금 pushd로 ~/one을 스택에 추가하여 현재 작업 디렉터리가 ~/one이 되었다고 가정해 봅시다. 첫 번째(또는 '0번째') 요소를 제거하려면 다음과 같이 입력합니다.
$ pwd
~/one
$ popd +0
/tmp ~/one/two/three ~/one ~/one/two/three/four/five ~/one/two/three/four
$ pwd
~/one
물론 0부터 시작하는 인덱스로 어떤 요소든 제거할 수 있습니다.
$ pwd
~/one
$ popd +2
/tmp ~/one/two/three ~/one/two/three/four/five ~/one/two/three/four
$ pwd
~/one
스택의 뒤에서부터 제거할 수도 있으며, 역시 0부터 시작합니다. 예를 들어 스택의 마지막 디렉터리를 제거하려면 다음과 같이 합니다.
$ popd -0
/tmp ~/one/two/three ~/one/two/three/four/five
이렇게 사용하면 popd는 작업 디렉터리를 변경하지 않고 스택만 조작합니다.
popd로 탐색하기
인수 없이 popd를 실행하면 기본적으로 스택의 첫 번째(0번째) 항목을 제거하고, 다음 항목을 현재 작업 디렉터리로 만듭니다.
이 기능은 빠른 디렉터리 전환 명령으로 가장 유용합니다. 예를 들어 서로 다른 두 디렉터리에서 작업하다가 잠시 다른 곳에 다녀와야 할 때, 복잡한 방문 기록이 필요 없다면 디렉터리 스택을 신경 쓸 필요조차 없습니다.
$ pwd
~/one
$ pushd ~/one/two/three/four/five
$ popd
$ pwd
~/one
pushd와 popd를 반드시 연달아 사용할 필요도 없습니다. pushd로 다른 위치를 방문한 후 버그 추적이나 조사 때문에 몇 시간을 보내더라도, 디렉터리 스택은 성실하게 기다리고 있습니다(단, 터미널 세션을 종료하지 않았다면 말이죠).
$ pwd
~/one
$ pushd /tmp
$ cd {/etc,/var,/usr}; sleep 2001
[...]
$ popd
$ pwd
~/one
실무에서의 pushd와 popd
pushd와 popd 명령어는 생각보다 훨씬 유용합니다. 한번 익혀두면 활용할 기회를 스스로 찾게 되고, 디렉터리 스택 개념에도 자연스럽게 익숙해집니다. 필자의 경우 pushd에 익숙해진 것이 git stash를 이해하는 데 큰 도움이 되었습니다. git stash는 pushd와 직접적인 관련은 없지만, 개념적으로 비슷하게 추상적인 도구입니다.
셸 스크립트에서 pushd와 popd를 사용하고 싶은 유혹이 들 수 있지만, 일반적으로는 피하는 것이 좋습니다. 이 명령어들은 Bash와 Zsh 외부에서는 이식성이 없고, 스크립트를 다시 읽을 때 직관적이지 않습니다(pushd +3보다는 cd $HOME/$DIR/$TMP 같은 표현이 훨씬 명확합니다).
이러한 주의사항을 감안하더라도, Bash나 Zsh를 자주 사용하는 개발자라면 pushd와 popd를 꼭 한번 시도해 볼 가치가 충분합니다.