Skip to content
isdnetworks
Go back

셸이 바꾼 경로와 실패한 호출

(수정됨)

docker exec 에 컨테이너 안의 /var/www/html 을 인자로 줬는데 엉뚱한 경로로 들어가는 바람에 명령이 실패했다. 오류 메시지에는 내가 준 적도 없는 C:/Program Files/Git/var/www/html 이 그대로 찍혀 있었다.

Table of contents

Open Table of contents

원인 — 인자가 바뀌어 들어간 경로

Git Bash 의 MSYS2 런타임이 슬래시로 시작하는 인자를 Windows 경로로 번역해 주는 기능을 갖고 있었다. MSYS2 공식 문서는 이 변환을 MSYS2_ARG_CONV_EXCL 로 접두 단위로 제외하는 방법을 적고 런타임 소스 msys2_path_conv.cc 는 MSYS_NO_PATHCONV 가 설정돼 있으면 변환을 통째로 건너뛴다. 컨테이너 안에서만 뜻이 있는 경로인데 호스트 경로로 바꿔서 넘긴 것이다.

두 가지 방법이 있었는데 MSYS_NO_PATHCONV=1 을 명령 앞에 붙이는 것과 //var/www/html 처럼 슬래시를 두 개 붙이는 것이다. 앞쪽을 골랐다. 이유는 뒤쪽은 왜 두 개인지가 코드에 안 드러나서다. 대신 그 변수를 모르는 다른 셸에서는 아무 뜻 없는 접두가 남는 것을 감수했다.

상황 — 한 환경에서만 나는 문제

같은 명령을 네 개 환경에서 돌려 보니 Git Bash 한 곳에서만 이 현상이 났다. macOS 의 zsh 와 Linux 의 bash 와 PowerShell 에서는 인자가 아무 변환 없이 그대로 전달되고 있었다.

한 환경에서만 나는 문제는 다른 사람이 재현하지 못하므로 내 자리에서는 된다는 말이 그대로 성립한다. 그래서 어느 환경에서 나는 문제인지를 먼저 확정해야 대화가 됐다.

해결 — 스크립트에서 흡수하기

명령을 쓰는 사람이 이 사정을 몰라도 되게 하려고 run.sh 에서 uname -o 가 Msys 일 때만 export MSYS_NO_PATHCONV=1 을 하게 했다. 변환이 없는 다른 환경에서는 그 분기가 아무 일도 하지 않는다.

이런 차이는 사용자에게 알리는 것보다 흡수하는 편이 낫다. 알려 줘도 매번 기억해야 하고 한 번 잊는 순간 같은 일이 다시 난다.

주의 — 호스트 경로와 컨테이너 경로

docker run -v 에서는 한 인자에 호스트 경로와 컨테이너 경로가 : 로 함께 들어간다. 앞의 것은 변환돼야 맞고 뒤의 것은 변환되면 안 되는 상황이었다.

그래서 HOST_DIR 을 pwd -W 로 미리 만들고 CTR_DIR 은 그대로 둔 뒤 -v "$HOST_DIR:$CTR_DIR" 로 조합했다. 한 문자열 안에서 서로 다른 규칙이 필요하면 그것을 분리하는 것이 유일한 방법이었다.

넘기는 것을 줄이기

근본적으로는 셸을 거쳐 넘기는 값 자체를 줄이는 쪽이 나았다. 실행할 내용을 .sh 파일에 넣고 그 경로만 넘기면 해석될 문자가 거의 남지 않는다.

같은 이유로 원격 실행에서는 셸이 자동으로 펼치거나 치환하는 것들도 함께 봐야 했다. 어느 계층에서 무엇이 해석되는지 헷갈릴 때는 printf '%s\n' "$@" 로 실제로 도착한 문자열을 먼저 출력해 보고 나서 진짜 명령을 넘겼다.

정리


Share this post on:

Previous Post
재현 못 하는 걸 다시 쓰지 않는다
Next Post
문서와 실제 응답의 어긋남