WSLでシェルスクリプトが動かない|CRLF・LFと改行の確認

Windowsで編集したシェルスクリプトをWSLへ持ってくると、ファイルはあるのに「bad interpreter」と表示されたり、普段は問題のないコマンドでエラーが出たりすることがあります。見た目では気づきにくい原因の一つが、行末に残ったCRという文字です。

CRLFはWindowsでよく使われる改行、LFはLinuxで一般的な改行です。WSLのBashで実行するスクリプトでは、改行をLFにそろえると解消する場合があります。まず行末を見て、元ファイルを残したコピーで確かめると、別の原因を見落としにくくなります。


行末にCRが残っていないかを見る

WSLのLinux端末で、対象スクリプトがあるフォルダーを開きます。以下ではファイル名をhello.shとして、GNU sedで先頭3行の見えない文字を表示します。UbuntuなどでGNU sedとBashが使える環境を前提にしています。

sed -n '1,3l' hello.sh

行末が\r$なら、改行の前にCRが残っています。LFだけの行末は$になります。ここで表示される$は行末を示す記号で、スクリプトに追記する文字ではありません。何も表示されなければ、ファイルの内容や選んだパスも見直してください。

たとえば先頭の#!/bin/bashがCRLFだと、直接実行時にインタープリターのパスの末尾までCRを含む文字列として扱われる場合があります。エラーに/bin/bash^Mが見えたときは、ファイルそのものの有無だけでなく、この先頭行にも注目すると原因を絞れます。

実行方法とエラーを照らし合わせる

内容を把握した自分のスクリプトなら、Bashに読み込ませる実行と、ファイルを直接起動する実行で違いが出ることがあります。

bash hello.sh

この実行では先頭のshebangでBashを選ぶのではなく、呼び出したBashが本文を読みます。それでも各行にCRが残っていれば、オプションやコマンドの一部として扱われてエラーになる可能性があります。途中のエラー後に処理が続く例もあるため、最後の出力や終了コードだけで成功と決めず、途中のエラーメッセージも読んでください。

./hello.sh

直接実行には実行権限と、先頭行に書いたインタープリターの存在も必要です。bad interpreterやNo such file or directoryという表示だけで、すべてをCRLFの問題とは判断できません。行末がLFなら、先頭行のパスや実行方法、実行権限へ確認を進められます。

元ファイルを残してLFのコピーを作る

行末のCRが原因として疑わしい場合は、別名の作業用コピーを作れます。出力先のhello-lf.shが未使用の名前であることを確認してから実行してください。同名ファイルがあると上書きされます。

sed 's/\r$//' hello.sh > hello-lf.sh

行末にあるCRだけを除いて、新しいファイルへ保存します。入力と出力に同じ名前を指定すると、読み取り前に元ファイルを空にしてしまうため、必ず別名にします。文字コード全体やBOMを変換する操作ではありません。

bash hello-lf.sh

LFのコピーでエラーが消えるかを確かめ、元のCRLF版と違いを見ます。問題が解消したら、普段のエディターでも対象ファイルの改行をLFにして保存すると、次の編集でCRLFに戻るのを防ぎやすくなります。どのファイルを直すかが分かるまでは、フォルダー全体の一括変換を避けてください。

Gitでシェルスクリプトの改行をそろえる

Gitで管理するプロジェクトでは、リポジトリの.gitattributesに次の規則を加える方法があります。既存の設定がある場合は上書きせず、同じファイルに適用される規則も含めて見直します。

*.sh text eol=lf

*.shに一致するファイルをテキストとして扱い、チェックアウト時の改行をLFにする指定です。Gitのグローバル設定を変える方法とは適用範囲が異なり、プロジェクト側に規則を置けます。

git check-attr text eol -- hello.sh

指定したファイルに適用される規則が、たとえば次のように表示されます。

hello.sh: text: set
hello.sh: eol: lf

規則の有効性と、現在のファイルの改行は別に確かめられます。追跡済みファイルなら、次のコマンドでインデックスと作業ファイルを見比べます。

git ls-files --eol -- hello.sh

i/lfはインデックス側、w/crlfは作業ファイル側の状態です。規則を追加しても、今開いている作業ファイルが即座に書き換わるわけではありません。i/lfとw/crlfが並ぶ状態なら、手元のCRLFが残っていると読めます。未追跡のファイルはこの一覧に出ないので、最初のsedによる確認も役立ちます。

既存リポジトリの正規化は差分を広く変えることがあります。まず対象スクリプトの改行と差分を確認し、チームの方針に合わせて取り込むと、内容の変更と改行の変更を追いやすくなります。

WSL containersでスクリプトをイメージへ入れる手順でも、LFのファイルを用意する点が関係します。改行を直した後にGit上の差分を確認したいときは、git diff –checkによる空白検査も使えますが、これはシェルが正しく実行できることを保証する検査ではありません。

参考資料

このブラウザからの自分のアクセスを解析から除外できます。