「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 を実パスにベタ書きする代わりに、env で PATH から探させると移植性が上がる。
#!/usr/bin/env python3
#!/usr/bin/env bash
env は PATH を走査してインタプリタを見つけるため、/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 の温床になる。スクリプトを扱うなら .gitattributes の eol=lf で明示的に上書きするのが確実。
エディタを LF 保存に設定する
- VS Code: 画面右下の
CRLF表示をクリックしてLFに変更。プロジェクトに.editorconfigを置きend_of_line = lfを指定すると自動化できる - vim:
:set fileformat=unixで保存 - Windows のメモ帳: シェルスクリプトの編集には使わない(CRLF を付けがち)
仕上げのチェックリスト
file script.shにCRLF line terminatorsが出ないhead -1 script.shの shebang のパスにwhichでインタプリタが実在するls -l script.shで実行ビット(x)が立っている
この3点が揃えば bad interpreter は再発しない。