Skip to content
isdnetworks
Go back

안 보이는 문자 하나가 스크립트를 막았다

Windows 에서 셸 스크립트를 쓰고 Linux 서버에 올렸다. 실행하니 오류 메시지가 나오는데 그 메시지 자체가 이상하게 잘려 보였다.

Table of contents

Open Table of contents

파일에 뭐가 들어 있나

cat 으로 보면 멀쩡했다. file 부터 쳐 봤다.

$ file run.sh
run.sh: POSIX shell script, ASCII text executable, with CRLF line terminators

with CRLF line terminators 가 붙어 있다. cat -A 로 안 보이는 문자까지 꺼냈다.

$ cat -A run.sh
#!/bin/sh^M$
cd /home/deploy/app^M$

줄마다 ^M이 붙어 있었다. 캐리지 리턴이다. $는 줄 끝 표시이고 그 앞의 ^M이 실제로 파일에 들어 있는 문자다.

Windows 는 줄바꿈을 CR LF 두 문자로 쓰고 Linux 는 LF 하나로 쓴다. Windows 에서 저장한 파일을 그대로 올리면 CR 이 줄마다 남는다.

왜 실행이 막히나

첫 줄 shebang 이 실행기 경로를 가리키는데 그 뒤에 CR 이 붙어 있다. 커널은 그 줄을 글자 그대로 경로로 쓴다. /bin/sh 가 아니라 /bin/sh\r 를 찾으니 없다고 한다.

$ ./run.sh
-bash: ./run.sh: /bin/sh^M: bad interpreter: No such file or directory

오류 메시지가 깨져 보인 것도 같은 이유였다. 메시지에 그 문자가 섞이면 커서가 줄 앞으로 돌아가면서 글자가 겹쳐 찍힌다.

명령 줄도 마찬가지다. 디렉터리를 옮기는 줄에서는 그 여분 문자까지 붙은 이름의 디렉터리를 찾는다. 눈에 안 보이는데 명령의 일부가 된다는 것이 이 문제의 성격이었다.

고치는 법과 재발 방지

지우는 방법은 여럿이다. tr -d '\r' 로 지우거나 sed 로 줄 끝을 치환하거나 dos2unix 를 쓴다.

$ sed -i 's/\r$//' run.sh

고쳐도 다음에 Windows 에서 저장하면 또 생긴다. 근본은 편집기 설정이라 줄바꿈 형식을 LF 로 바꾸고 새 파일 기본값도 같이 바꿨다.

저장소 쪽에도 걸어 뒀다. SVN 은 파일에 svn:eol-style 프로퍼티를 붙일 수 있다. native 로 주면 받는 쪽 운영체제에 맞춰 나온다.

$ svn propset svn:eol-style native run.sh

올리는 방법에 따라 자동으로 바뀌기도 한다. FTP 의 ASCII 모드는 줄바꿈을 변환하고 BINARY 모드는 안 한다. 텍스트 파일을 BINARY 로 올리면 CR 이 그대로 간다. 이 차이 때문에 어제는 되던 것이 오늘은 안 되는 상황이 생겼다. 파일은 그대로이고 올리는 방법만 바뀌었을 뿐이었다.

다른 데서도 터진다

셸 스크립트만 문제가 아니었다. 설정 파일에서는 값 끝에 그 문자가 붙는다. 정수로 읽으면 변환하다 죽는데, 문자열로 읽으면 안 죽고 그냥 안 맞는 값이 된다. 뒤쪽이 훨씬 찾기 어렵다.

탭으로 나눈 자료를 LOAD DATA INFILE 로 넣을 때도 마지막 컬럼 값 끝에 붙는다. MySQL 에는 잘 들어가고 조회할 때만 안 맞는다. 저장된 값에 안 보이는 문자가 하나 더 있기 때문이다.

값이 안 맞는데 눈으로는 같아 보이면 길이를 센다. MySQL 이면 LENGTH() 다. 다섯 글자인데 여섯이 나오면 그것이다. 파일이면 cat -Aod -c 로 바이트를 본다. 눈으로 안 보이는 문제는 눈이 아닌 방법으로 봐야 한다.

정리


Share this post on:

Previous Post
화면 파일에 업무 로직이 있었다
Next Post
같은 값이 두 곳에 있었다