[bash] /bin/sh^M: bad interpreter

sass 컴파일을 하려고 watch.sh를 실행했더니 이런 메시지가 뜨면서 실행되지 않았다.

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

sh 파일의 맨 앞에 선언한 인터프리터가 /bin/sh인데, 여기에 ^M 문자가 붙으면서, “/bin/sh^M 같은 인터프리터는 없는데?” 하고 에러 메시지가 나온 것이다.

^M 문자는 윈도우에서 리턴값을 표시하는 문자의 일부다. 보통은 r로 많이 봤을 것이다. 윈도우는 리턴값을 rn로 표시하고 유닉스 계열은 n으로 표시하는데, 윈도우에서 (혹은 윈도우 형식으로) 생성한 리턴값을 유닉스에서 읽으면서 n만을 리턴값으로 인식, r은 그냥 문자열로 인식하면서 문제가 생기는 것이다.

r, rn, n의 OS별 사용은 다음과 같다고 한다.

  • DOS & Windows: rn 0D0A (hex), 13,10 (decimal)
  • Unix & Mac OS X: n, 0A, 10
  • Macintosh (OS 9): r, 0D, 13

개발자라면 코드를 작성해서 r 문자를 잡아도 될 것이다. 물론 커맨드라인에서 sed를 이용해 간편하게 제거하는 방법이 있다. 제거하는 방법은 아래 글을 참조했다.

Remove CTRL-M characters from a file in UNIX

명령어는 아래와 같다.

sed -i "s|{^M문자 입력 버튼 누르기}||g" watch.sh

^M문자 입력 버튼 누르기에서는 Ctrl + v, m을 누르면 된다. 그러면 ^M 문자가 입력되는 것을 볼 수 있을 것이다. Ctrl을 떼지 말고 v, m을 연이어 누르는 것이 중요하다.

해설

  • sed는 문서 편집기다.
  • -i 옵션은, 변환 결과를 표준 출력으로 내뱉지 말고 원본 파일에 그대로 덮어 쓰라는 옵션이다.
    원본 파일을 덮어쓰기 싫으면 > 파이프를 사용해서 다른 파일로 만들어라. sed "s|^M||g" watch.sh > watch2.sh
  • "s|^M||g"에서 s는 substitute의 약자로 교체하라는 뜻이다.
    |는 구분자다. /를 구분자로 사용해도 되는데, url 변환을 많이 하다 보니 |를 구분자로 사용하는 게 습관이 됐다.
    뒤에 붙은 g 플래그는 Global의 약어로, 나오는 모든 것을 바꾸라는 뜻이다. 안 그러면 처음 나오는 거 하나만 바꾼다.
    그래서 "s|^M||g"은 모든 ^M을 빈 값으로 교체하라는 뜻이 된다.

카테고리 글 목록 👉

대표글

댓글 남기기