리눅스 realpath 명령어 사용법 - 절대경로 정규화와 스크립트 기준 디렉터리 잡기
이 명령어를 언제 쓰는가
셸 스크립트가 "어디서 실행되든 똑같이 동작"하게 만들 때 쓴다. 스크립트 안에서 ./config/app.conf 같은 상대경로를 쓰면 호출한 사람의 현재 디렉터리에 따라 결과가 달라진다. realpath로 한 번 절대경로로 고정해 두면 이 문제가 사라진다.
운영에서는 심볼릭 링크를 걷어낼 때 더 자주 쓴다. /opt/app/current가 실제로 어느 릴리스 디렉터리를 가리키는지, /var/log가 별도 볼륨의 어디로 연결돼 있는지 확인해야 배포 사고를 막을 수 있다. ..와 //, 끝의 슬래시까지 전부 정리해 주는 것도 장점이다.
기본 형식
realpath [옵션] 경로...
경로를 여러 개 주면 한 줄에 하나씩 결과를 낸다. 기본 동작은 마지막 요소를 뺀 나머지가 전부 존재해야 하고, 심볼릭 링크는 모두 따라간다는 것이다(GNU man 페이지의 all but the last component must exist). 즉 realpath ./out/new.log는 ./out만 있으면 성공하지만, 중간 디렉터리가 없으면 종료 코드 1과 함께 에러를 낸다.
자주 쓰는 옵션
| 옵션 | 의미 | 예시 |
|---|---|---|
| -e | 마지막 요소까지 전부 존재해야 한다. 기본값보다 엄격 | realpath -e ./conf |
| -m | 아무것도 존재하지 않아도 된다. 만들 파일의 경로 계산용 | realpath -m ./out/new.log |
| -s | 심볼릭 링크를 따라가지 않고 문자열만 정규화 | realpath -s /opt/app/current |
| --relative-to=D | D 기준의 상대경로로 출력 | realpath --relative-to=/opt /opt/app/bin |
| -q | 에러 메시지를 숨긴다(종료 코드로만 판단) | realpath -q "$p" |
| -z | 줄바꿈 대신 NUL로 구분. xargs -0와 짝 | realpath -z * |
실전 예제
1) 스크립트가 자기 위치를 기준으로 파일을 찾게 한다. 크론이나 systemd에서 실행될 때 현재 디렉터리가 /여도 안전하다.
#!/bin/bash
set -euo pipefail
SCRIPT="$(realpath "$0")"
BASE="$(dirname "$SCRIPT")"
source "$BASE/lib/common.sh"
2) 배포 심볼릭 링크가 실제 어느 릴리스를 보는지 확인한다. 롤백 전에 반드시 하는 확인이다.
realpath /opt/app/current
/opt/app/releases/2026-08-25T1130
3) 아직 만들지 않은 출력 디렉터리·파일의 절대경로를 계산한다. 파일 이름만 없는 경우는 기본 동작으로도 되지만, out 디렉터리 자체가 없을 수 있으므로 -m이 안전하다.
OUT="$(realpath -m "${1:-./out}/report-$(date +%F).csv")"
mkdir -p "$(dirname "$OUT")"
4) 사용자 입력이 허용된 디렉터리 밖으로 나가지 않는지 검사한다. ../../etc/passwd 같은 경로 탈출을 막는 기본 패턴이다.
ROOT=/srv/uploads
TARGET="$(realpath -m "$ROOT/$USER_INPUT")"
case "$TARGET" in
"$ROOT"/*) echo "ok: $TARGET" ;;
*) echo "경로 탈출 시도" >&2; exit 1 ;;
esac
5) 절대경로를 특정 기준의 상대경로로 바꾼다. tar나 rsync 인자를 만들 때 편하다.
realpath --relative-to=/opt/app /opt/app/logs/2026/08
logs/2026/08
함정과 주의점
"어디까지 존재해야 하는가"가 옵션마다 다르다. 기본값은 마지막 요소만 없어도 되고, -e는 전부 있어야 하며, -m은 하나도 없어도 된다. 아직 만들지 않은 디렉터리 아래 경로를 기본값으로 계산하면 No such file or directory로 실패하고, set -e가 걸려 있으면 그 자리에서 스크립트가 종료된다. 반대로 반드시 있어야 하는 입력을 기본값으로 검사하면 오타 난 파일명이 통과해 버린다. 만들 대상이면 -m, 있어야 하는 입력이면 -e로 의도를 명시하라.
macOS의 realpath는 GNU와 다르다. 이 글의 -m, -s, --relative-to는 GNU coreutils 기능이다. macOS에 기본 탑재된 realpath는 사실상 -q 정도만 받으며, 옵션을 주면 illegal option으로 실패한다. 맥에서 개발한 스크립트를 서버에 올릴 때 흔히 터진다. 맥에서는 brew install coreutils 후 grealpath를 쓰거나, 이식성이 필요하면 cd "$(dirname "$0")" && pwd -P로 대체한다.
아주 오래된 서버에는 realpath가 아예 없다. realpath가 coreutils에 들어온 것은 8.15(2012)부터라, CentOS 6 계열 등에는 없거나 별도 패키지다. 그런 환경에서는 readlink -f가 사실상 같은 일을 한다. 반대로 최신 환경만 다룬다면 의도가 분명한 realpath 쪽이 읽기 좋다.
-s는 링크를 따라가지 않는다. /opt/app/current/bin을 -s로 정규화하면 링크가 그대로 남은 채 ..만 정리된다. 실제 파일 위치를 알아야 하는 상황에서 -s를 쓰면 엉뚱한 경로를 얻는다.
함께 보면 좋은 명령어
- readlink —
readlink -f는 realpath의 사실상 동의어이며 구형 서버에서 대체제가 된다. - dirname / basename — realpath로 고정한 절대경로를 디렉터리와 파일명으로 쪼갤 때 짝으로 쓴다.
- pwd —
pwd -P는 현재 디렉터리의 심볼릭 링크를 걷어낸 실제 경로를 준다.