問題の発生
Windows上で完璧な entrypoint.sh スクリプトを書き終えたところだとします。スムーズな起動を期待して docker-compose up を実行しますが、コンテナは即座にクラッシュし、次のような紛らわしいエラーが表示されます。
standard_init_linux.go:228: exec user process caused: no such file or directory
また、ログを確認すると、次のような具体的な原因が表示されることもあります。
env: 'bash\r': No such file or directory
ファイルは確かにそこに存在しているのに、なぜこのようなエラーが出るのでしょうか。フォルダ内にも見えますし、エディタで開くこともできます。では、なぜ Docker は「存在しない」と主張するのでしょうか?
根本的な原因:見えない文字
問題はコードそのものではなく、OSが各行の末尾にある見えない「エンターキー(改行)」をどのように保存しているかにあります。Windowsは CRLF(キャリッジリターン + ラインフィード)を使用し、\r\n という2つの隠し文字を追加します。一方、Linuxは LF(ラインフィード)、つまり \n のみを使用します。
Linuxベースの Docker コンテナがスクリプトを読み込む際、#!/bin/bash\r として認識されます。システムは bash\r という名前のプログラムを探そうとしますが、Linuxの /bin/ ディレクトリには \r(キャリッジリターン)を含むプログラムは存在しないため、実行に失敗します。スクリプトのすべての行が、実質的にこの余分な1バイトの文字によって「汚染」されている状態です。
CRLF問題の特定方法
標準的なテキストエディタではこれらの文字は見えません。確認するには、WSL または Linux ターミナルで次のコマンドを実行します。
cat -e your-script.sh
ターミナルですべての行の末尾に ^M$ と表示される場合、それは CRLF 改行コードであることを意味します。クリーンな Linux 互換ファイルでは $ 記号のみが表示されるはずです。
解決策1:VS Codeで改行コードを切り替える
Visual Studio Code を使えば、この修正は非常に簡単です。コマンドラインすら必要ありません。
entrypoint.shやsetup.shファイルを開きます。- 右下のステータスバーを確認します。おそらく CRLF と表示されています。
- CRLF をクリックし、ポップアップメニューから LF を選択します。
- ファイルを保存します。
これで、イメージを再ビルドしてください。この手動の修正は、単一ファイルの素早いデバッグに最適です。
解決策2:dos2unix ユーティリティを使用する
多数のスクリプトがある場合、手動で変更するのは時間の無駄です。キャリッジリターンを一括で削除する専用ツール dos2unix を使いましょう。
Ubuntu または WSL で、次のコマンドを使ってインストールします。
sudo apt-get install dos2unix
dos2unix script1.sh script2.sh
このユーティリティは、コードをリポジトリにプッシュする前に改行コードを修正するための標準的な手法です。
解決策3:Dockerfile内で修正を自動化する
開発者がファイルを LF で保存することを忘れないように期待するのはリスクがあります。sed を使用して Dockerfile 内に直接セーフガードを構築できます。これにより、誰かが間違った設定でリポジトリをクローンしても、スクリプトが確実に動作するようになります。
FROM alpine:3.18
COPY entrypoint.sh /entrypoint.sh
# 万が一に備えてWindowsの改行コードを強制的に削除
RUN sed -i 's/\r$//' /entrypoint.sh
RUN chmod +x /entrypoint.sh
ENTRYPOINT ["/entrypoint.sh"]
sed コマンドは各行の末尾にある \r 文字を検索して削除します。ビルド時間は1秒も増えませんが、何時間ものトラブルを未然に防ぐことができます。
解決策4:Gitの改行コード処理を設定する
Git for Windows は、git clone 時に LF を CRLF に自動変換することがよくあります。この「親切な」機能こそが、Docker スクリプトを壊す原因です。これはグローバルまたはプロジェクト単位で無効にできます。
グローバル設定での修正:
git config --global core.autocrlf input
より良い方法 (.gitattributes):
プロジェクトのルートに .gitattributes ファイルを作成します。これにより、ユーザーの OS 設定に関係なく、Git はシェルスクリプトに対して常に LF を使用するよう強制されます。
*.sh text eol=lf
Dockerfile text eol=lf
保存後、ローカルファイルをリセットして変更を適用します:
git rm --cached -r .
git reset --hard
最終確認
修正が成功したか確認するには、file コマンドを使用します。
file entrypoint.sh
出力結果が "Bourne-Again shell script, ASCII text executable" であれば準備完了です。もし依然として "with CRLF line terminators" と表示される場合は、変換に失敗しています。隠れた \r 文字が消えれば、Docker コンテナはようやく期待通りに起動します。

