「bad interpreter」エラーの直し方 - shebang と CRLF 改行

「bad interpreter」エラーの直し方 - shebang と CRLF 改行

「bad interpreter」エラーとは何か?

結論: シェルがスクリプト1行目の shebang を解釈できないエラー。原因のほぼ全ては「CRLF 改行の混入」か「shebang のパス誤り」の2つ。

シェルスクリプトを実行しようとして、次のようなエラーが出た経験はないだろうか。

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

ファイルは存在し、実行権限もあるのに動かない。このエラーは shebang 行(1行目の #!...)に書かれたインタプリタをカーネルが起動できない ときに発生する。

まず原因を2つに絞る

  • エラーに ^M が見える → CRLF 改行が原因(最頻出)
  • ^M が無く /usr/bin/python3 等が出る → shebang のパスが存在しない

この記事は上から順に切り分ける。

なお Permission denied は実行ビット(chmod +x)の問題で、原因の層が異なる。混同しやすいので、権限側の切り分けは Permission denied の直し方 を参照。

なぜ「No such file or directory」と言われるのか?

結論: カーネルは shebang 行を文字列のまま interpreter のパスに使う。CRLF の \r が付くと /bin/bash\r という存在しないパスを探すため「No such file or directory」になる。

Linux カーネルは #! で始まる1行目を読み、#! の直後を インタプリタの絶対パスとしてそのまま 使う。ここがエラーの本質。

Windows や一部のエディタで保存したファイルは、改行が LF\n)ではなく CRLF\r\n)になる。すると shebang 行はこう解釈される。

#!/bin/bash\r
       ↑ この \r(CR)まで含めてパス扱い

つまりカーネルは /bin/bash ではなく /bin/bash + 復帰文字 という名前のファイルを探す。そんなファイルは存在しないので No such file or directory、エラー表示上は CR が ^M として見える。

ファイル名やパスが正しくても、目に見えない \r 1文字 で失敗する。これが「見た目は正しいのに動かない」の正体。

shebang のパスそのものが間違っているケースもある。例えば #!/usr/local/bin/python3 と書いたが、その環境では Python が /usr/bin/python3 にしかない場合などだ。

CRLF 改行が原因か、どう見分けるか?

結論: file で改行コード種別、cat -A で行末の ^M を確認する。どちらも CRLF を一目で判定できる。

推測で直す前に、必ず原因を観測する。

file コマンドで改行種別を見る

$ file deploy.sh

CRLF が混入していると、こう表示される。

deploy.sh: Bourne-Again shell script, ASCII text executable, with CRLF line terminators

with CRLF line terminators が出れば改行コードが原因で確定。正常なら ASCII text executable のみで CRLF の表記は出ない。

cat -A で行末を可視化する

$ cat -A deploy.sh | head -3
#!/bin/bash^M$
^M$
echo "deploy start"^M$

cat -A は行末を $、CR を ^M で表示する。各行末が ^M$ になっていれば CRLF。正常なファイルは $ だけになる。

shebang 行だけを厳密に見る

$ head -1 deploy.sh | od -c
0000000   #   !   /   b   i   n   /   b   a   s   h  \r  \n

\r \n が並んでいれば CRLF。\n だけなら LF(正常)。

CRLF 改行をどう修正するか?

結論: dos2unix が最も確実。無ければ sed -i 's/\r$//' で全行の末尾 CR を除去する。修正後は再び file で確認する。

方法1: dos2unix(推奨)

$ dos2unix deploy.sh
dos2unix: converting file deploy.sh to Unix format...

CRLF を LF に変換する専用ツール。インストールは Ubuntu/Debian なら sudo apt install dos2unix、RHEL 系なら sudo dnf install dos2unix

方法2: sed(追加インストール不要)

dos2unix が入っていない環境では sed で代用できる。

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

s/\r$// は「各行末の CR を削除」の意味。-i でファイルを直接書き換える。心配なら -i.bak でバックアップを残せる。

$ sed -i.bak 's/\r$//' deploy.sh   # deploy.sh.bak を残す

tr -d '\r' を使う場合、tr は標準入力専用なので 同じファイルへの上書きリダイレクトは不可(中身が消える)。必ず別ファイルに出す。

$ tr -d '\r' < deploy.sh > deploy.unix.sh   # OK
$ tr -d '\r' < deploy.sh > deploy.sh         # NG: 空になる

方法3: vim で変換

エディタで開いている最中なら、その場で直せる。

:set fileformat=unix
:w

修正できたか必ず確認する

$ file deploy.sh
deploy.sh: Bourne-Again shell script, ASCII text executable
$ ./deploy.sh
deploy start

CRLF line terminators の表記が消えていれば成功。

shebang のパス間違いをどう直すか?

結論: shebang のパスにインタプリタが実在するか which で確認する。移植性を上げるなら #!/usr/bin/env bash を使う。

^M が出ず、bash: ./run.sh: /usr/local/bin/python3: bad interpreter のようにパスが表示される場合は、そのパスにインタプリタが無い。

インタプリタの実在を確認する

$ head -1 run.sh
#!/usr/local/bin/python3
$ which python3
/usr/bin/python3

shebang は /usr/local/bin/python3 を指しているが、実体は /usr/bin/python3。パスが食い違っている。

env を使って解決する

shebang を実パスにベタ書きする代わりに、envPATH から探させると移植性が上がる。

#!/usr/bin/env python3
#!/usr/bin/env bash

envPATH を走査してインタプリタを見つけるため、/usr/bin/usr/local/bin のどちらにあっても動く。環境差で壊れにくい、現代的な書き方だ。

ただし env 経由ではインタプリタへの引数指定に制約がある(古い環境では複数引数を渡せない)。set -euo pipefail 等はスクリプト本体に書けばよく、shebang に詰め込む必要はない。

再発をどう防ぐか?

結論: .gitattributes.sh を LF 固定、エディタを LF 保存に設定する。この2点で CRLF の混入をほぼ封じられる。

一度直しても、保存・コミットのたびに CRLF が戻ると意味がない。発生源を断つ。

Git で改行を固定する

リポジトリ直下に .gitattributes を置き、シェルスクリプトを LF に固定する。

*.sh text eol=lf

これでチェックアウト時も常に LF になり、Windows 環境から触られても壊れにくい。

core.autocrlf の設定も確認しておく。Linux/macOS では input が無難だ。

$ git config --global core.autocrlf input

core.autocrlf=true は Windows 開発者がよく設定するが、チェックアウト時に CRLF を付けるため、シェルスクリプトでは bad interpreter の温床になる。スクリプトを扱うなら .gitattributeseol=lf で明示的に上書きするのが確実。

エディタを LF 保存に設定する

  • VS Code: 画面右下の CRLF 表示をクリックして LF に変更。プロジェクトに .editorconfig を置き end_of_line = lf を指定すると自動化できる
  • vim: :set fileformat=unix で保存
  • Windows のメモ帳: シェルスクリプトの編集には使わない(CRLF を付けがち)

仕上げのチェックリスト

  1. file script.shCRLF line terminators が出ない
  2. head -1 script.sh の shebang のパスに which でインタプリタが実在する
  3. ls -l script.sh で実行ビット(x)が立っている

この3点が揃えば bad interpreter は再発しない。

次に読む