본문으로 건너뛰기

Shell 스크립트 'No such file or directory' 오류 완벽 해결법

· 약 6분
Jeongyong Park
쌍팔년생 개발자

eol

안녕하세요, 쌍팔년생 개발자입니다.

작년에 팀에서 배포 자동화 스크립트를 만들면서 정말 당황스러운 일이 있었어요. Windows에서 열심히 작성한 Shell 스크립트를 리눅스 서버에 올렸는데, 아무리 실행해도 #!/bin/bash: No such file or directory 오류만 계속 나오는 거예요... 😰

파일은 분명히 존재하고, 권한도 맞는데 왜 "파일이 없다"고 하는지 정말 이해할 수 없었어요. 팀원들과 함께 몇 시간을 디버깅했는데 원인을 찾지 못해서 정말 답답했습니다.

그러던 중 스택오버플로우에서 비슷한 문제를 겪은 분의 글을 발견했어요. "혹시 줄바꿈 문제는 아닐까요?"라는 댓글을 보고 cat -v 명령어로 파일을 확인해보니... 바로 그것이었습니다! Windows와 Linux의 줄바꿈 차이 문제였어요.

TL;DR: Windows에서 작성한 스크립트의 CRLF 줄바꿈이 Linux에서 문제를 일으킵니다. dos2unix 명령어나 sed 's/\r$//'로 해결하고, Git 설정과 .gitattributes로 예방하세요.

저희가 겪었던 문제 상황

당황스러웠던 첫 번째 에러

팀에서 CI/CD 파이프라인을 구축하면서 Windows 개발 환경에서 배포 스크립트를 작성했어요. 로컬에서는 Git Bash로 테스트해서 잘 동작했는데, 리눅스 서버에 올리니까 이런 오류가 나오는 거예요:

line 1: #!/bin/sh: No such file or directory

처음에는 "어? 권한 문제인가?" 하면서 chmod +x도 해보고, 경로도 확인해봤는데 모든 게 정상이었어요. 정말 이상했죠.

동료와 함께한 디버깅 과정

팀장님과 시니어 개발자분이 함께 원인을 찾아보자고 하셨어요. 처음에는 다음과 같은 것들을 시도해봤습니다:

# 파일이 정말 있는지 확인
ls -la deploy.sh

# 권한 문제인지 확인
chmod +x deploy.sh

# 직접 bash로 실행해보기
bash deploy.sh

그런데 이상하게도 bash deploy.sh로 직접 실행하면 동작하는데, ./deploy.sh로는 안 되는 거예요. "이게 뭐지?"라는 생각이 계속 들었어요.

시니어 개발자의 조언

그때 시니어 개발자분이 "제가 예전에 비슷한 문제를 겪어본 적이 있는데, 줄바꿈 문제일 수도 있어요"라고 하시면서 이런 명령어를 알려주셨어요:

# 파일의 숨겨진 문자들을 보기
cat -v deploy.sh

실행해보니까 각 줄 끝에 ^M 이라는 이상한 문자가 붙어있더라고요! "아, 이게 문제였구나!"라는 생각에 정말 깨달음이 왔어요.

왜 이런 문제가 발생하는지 알게 된 과정

운영체제별 줄바꿈 방식의 차이

시니어 개발자분이 친절하게 설명해주셨어요:

운영체제줄바꿈 문자16진수 표현설명
Windows/DOS\r\n0D 0ACarriage Return + Line Feed
Unix/Linux\n0ALine Feed만 사용

"Windows에서는 줄바꿈이 두 개 문자로 표현되는데, Linux에서는 하나만 쓰거든요. 그래서 shebang이 /bin/bash\r로 인식되는 거예요"라고 설명해주시니까 이해가 됐어요.

문제를 확인하는 방법들

동료분이 알려준 여러 가지 확인 방법들:

# 16진수로 파일 내용 확인
hexdump -C script.sh | head

# 시각적으로 확인
cat -v script.sh

# 더 자세한 정보
od -bc script.sh

이런 명령어들을 써보니 문제를 정확히 파악할 수 있었어요.

여러 해결 방법을 시도해본 경험

1. dos2unix 명령어 (가장 효과적이었던 방법)

시니어 개발자분이 "가장 간단한 방법"이라고 추천해주신 방법이에요:

# dos2unix 설치
sudo apt-get install dos2unix

# 파일 변환
dos2unix deploy.sh

실행해보니까 정말 간단하게 해결되더라고요! "이런 편리한 도구가 있었구나!"라는 생각이 들었어요.

2. sed 명령어로 직접 해결

팀 내 리눅스 고수분이 "sed로도 할 수 있어요"라고 알려주신 방법:

# 캐리지 리턴 문자 제거
sed -i 's/\r$//' deploy.sh

# 원본 파일 백업하면서 변환
sed -i.bak 's/\r$//' deploy.sh

이 방법도 잘 동작했는데, "sed 정말 만능이네요"라고 감탄했던 기억이 있어요.

3. vim에서 직접 변환

에디터에서 바로 해결하는 방법도 배웠어요:

# vim으로 파일 열기
vim deploy.sh

# 명령 모드에서
:set ff=unix
:wq

"에디터에서도 이런 게 되는구나!" 하면서 또 하나 배웠죠.

재발 방지를 위한 팀 차원의 대책

Git 설정으로 예방하기

이 문제를 겪고 나서 팀에서 재발 방지책을 논의했어요. 팀장님이 "앞으로는 이런 문제가 없도록 Git 설정을 통일하자"고 하셨어요:

# 팀 전체가 이 설정을 적용하기로 했어요
git config --global core.autocrlf false
git config --global core.eol lf

.gitattributes 파일 생성

프로젝트 루트에 .gitattributes 파일을 만들어서 팀 차원에서 관리하기로 했어요:

# 모든 텍스트 파일은 LF 사용
* text=auto eol=lf

# 스크립트 파일은 반드시 LF 사용
*.sh text eol=lf
*.bash text eol=lf

# Windows 배치 파일은 CRLF 사용
*.bat text eol=crlf
*.cmd text eol=crlf

팀원분이 "이렇게 하면 앞으로는 자동으로 처리되겠네요!"라고 하시면서 모두 만족스러워했어요.

VS Code 설정 통일

저희 팀이 VS Code를 주로 사용해서 설정도 통일했어요:

{
"files.eol": "\n",
"files.insertFinalNewline": true,
"files.trimFinalNewlines": true
}

"개발 환경부터 통일하는 게 중요하네요"라는 것을 깨달았어요.

실무에서 유용했던 팁들

대량 파일 처리 스크립트

나중에 비슷한 문제가 또 생겼을 때를 대비해서 동료분과 함께 처리 스크립트를 만들어뒀어요:

#!/bin/bash
# fix_line_endings.sh - 팀에서 공유하는 스크립트

EXTENSIONS=("sh" "bash" "py" "pl")

for ext in "${EXTENSIONS[@]}"; do
echo "Converting *.${ext} files..."
find . -name "*.${ext}" -type f -exec dos2unix {} \;
done

echo "Line ending conversion completed!"

파일 형식 확인 스크립트

문제가 생겼을 때 빠르게 확인할 수 있는 스크립트도 만들었어요:

#!/bin/bash
# check_line_endings.sh

check_file() {
local file="$1"
if file "$file" | grep -q "CRLF"; then
echo "DOS/Windows: $file"
elif file "$file" | grep -q "CR"; then
echo "Mac (old): $file"
else
echo "Unix/Linux: $file"
fi
}

for file in "$@"; do
if [ -f "$file" ]; then
check_file "$file"
else
echo "File not found: $file"
fi
done

배운 점과 팀에 미친 영향

개발 프로세스 개선

이 경험을 통해 저희 팀의 개발 프로세스가 많이 개선되었어요:

  1. 개발 환경 설정 문서화: 새로운 팀원이 오면 첫날에 Git 설정부터 안내
  2. CI/CD 파이프라인에 검증 단계 추가: 스크립트 실행 전 자동으로 줄바꿈 확인
  3. 코드 리뷰 체크리스트에 추가: Windows에서 작성한 스크립트는 줄바꿈 확인 필수

팀 지식 공유 문화

시니어 개발자분이 "이런 삽질을 다른 팀원들도 겪을 수 있으니 공유해야죠"라고 하시면서 팀 위키에 문서를 만들게 되었어요.

덕분에 나중에 새로 온 팀원분들은 이런 문제를 겪지 않을 수 있게 되었고, "아, 이런 것도 미리 생각해서 공유하는 게 중요하구나"라는 것을 배웠어요.

마무리

처음에는 정말 이상한 오류라고 생각했는데, 알고 보니 운영체제 간의 차이 때문에 생기는 흔한 문제였어요. 하지만 이 경험 덕분에 여러 가지를 배울 수 있었습니다:

  • 문제 해결 과정의 중요성: 혼자 끙끙대지 말고 팀원들과 함께 해결하기
  • 근본 원인 파악: 표면적인 문제가 아닌 진짜 원인 찾기
  • 재발 방지: 일회성 해결이 아닌 시스템적 접근
  • 지식 공유: 개인의 경험을 팀 전체의 자산으로 만들기

특히 시니어 개발자분의 조언 덕분에 빠르게 해결할 수 있었고, 팀 차원에서 재발 방지책까지 마련할 수 있어서 정말 좋은 경험이었어요.

아직도 가끔 다른 프로젝트에서 비슷한 문제를 겪는 분들을 보면 이때의 경험을 공유해드리곤 해요. 완벽한 해결책은 아니지만, 비슷한 문제로 고민하고 계신 분들께 도움이 되길 바라며 정리했습니다.

혹시 다른 좋은 해결 방법이나 비슷한 경험이 있으시면 언제든 댓글로 공유해주세요! 함께 배워가면 좋겠어요.

참고 자료

📢 AdSense 광고 영역로딩 중...

💬 댓글 시스템