셸 스크립트에서 심볼릭 링크 해결하는 방법

유닉스 계열 시스템에서 심볼릭 링크(또는 symlink)를 다루는 것은 경우에 따라 까다로울 수 있습니다. 특히 symlink가 가리키는 실제 경로를 찾고자 할 때 더욱 그렇습니다. 셸 스크립트를 작성하고 중간 심볼릭 링크를 해결한 후 대상의 전체 경로를 결정해야 한다면, 여기서 해결책을 찾을 수 있습니다. 이 블로그 게시물에서는 이를 효율적으로 달성하는 방법을 설명할 것입니다.

문제 이해하기

심볼릭 링크 foo가 다른 디렉토리 bar를 가리키는 상황을 상상해 보세요. cd foopwd 같은 명령어를 실행할 때, 셸은 하위 구조를 명확히 드러내지 않아 대상의 전체 경로를 유추하기 어렵게 만듭니다.

예를 들어:

ls -ld foo bar
drwxr-xr-x   2 greg  greg  68 Aug 11 22:36 bar
lrwxr-xr-x   1 greg  greg   3 Aug 11 22:36 foo -> bar

다음과 같이 실행하면:

cd foo
pwd

출력은 단순히 /Users/greg/tmp/foo일 것입니다. 이는 foo가 가리키는 실제 경로인 /Users/greg/tmp/bar를 찾고자 할 때 별로 도움이 되지 않습니다.

해결책

다행히도, C 프로그래밍에 깊이 들어가지 않고도 셸 스크립트에서 symlink를 해결할 수 있는 내장 명령어들이 있습니다. 다음은 이를 수행하는 방법입니다:

pwd 명령어 사용하기

명령어 pwd -P는 현재 작업 디렉토리를 인쇄하는 데 사용되며, 모든 symlink를 해결하여 대상의 절대 경로를 제공합니다. pwd -P를 실행하면:

pwd -P

모든 symlink를 해결한 후 전체 경로를 반환합니다.

getcwd 사용하기

또 다른 방법은 C의 unistd.h 라이브러리에서 getcwd 함수를 활용하는 것입니다. 하지만 스크립팅을 할 경우, 단순히 셸 명령어를 사용할 수 있습니다. getcwdpwd -P와 유사한 동작을 한다는 것을 아는 것이 좋습니다.

해결 함수 만들기

이 명령어들을 함수로 감싸면 작업이 더 수월해집니다. 다음은 Bash 셸에서 간단한 resolve 함수의 예입니다:

resolve() {
    # 제공된 경로를 사용하여 해결합니다
    local target=$1
    # `readlink -f`는 symlink를 따라가며 전체 경로를 반환합니다
    local full_path=$(readlink -f "$target")
    echo "$full_path"
}

예제 사용법

이제 함수를 다음과 같이 호출하면:

resolve "foo"

출력은 다음과 같습니다:

/Users/greg/tmp/bar

이 패턴은 셸 스크립트 환경에서 만난 모든 symlink의 전체 경로를 접근할 수 있게 해줍니다.

보너스: 사용자 홈 경로 해결하기

티르드 표기법(예: ~username)을 사용하여 홈 디렉토리를 해결하려면, Bash는 자동으로 이러한 경로를 확장합니다. 따라서 이를 resolve 함수와 원활하게 결합할 수 있습니다.

결론

셸 스크립트에서 심볼릭 링크를 해결하는 것은 복잡할 필요가 없습니다. pwd -P 명령어를 사용하거나 readlink를 사용하는 resolve와 같은 도우미 함수를 생성함으로써, 대상의 전체 경로를 효과적으로 결정할 수 있습니다. 이 기술은 유닉스 계열 환경에서 작업하는 누구에게나 필수적이며 스크립트를 훨씬 더 강력하고 유용하게 만드는 데 도움을 줍니다.

심볼릭 링크를 잘 관리하면 디렉토리 구조를 탐색하거나 복잡한 셸 스크립트를 작성하는 동안 시간과 혼란을 절약할 수 있습니다.