クロスプラットフォームスクリプトの行末

シェルスクリプトが常にLFを使用し、バッチスクリプトが常にCRLFを使用するように.gitattributesを設定し、OS間での実行エラーを防ぐ方法。

Best Practices

詳細な説明

スクリプトファイルの行末

スクリプトファイルは不正な行末に対して最も敏感なファイルの1つです。CRLF行末のbashスクリプトはUnixで実行できず、LF行末のバッチファイルはWindowsで誤動作する可能性があります。これはtext=autoだけでは不十分な領域であり、明示的なeolディレクティブが必要です。

推奨設定

# Unixスクリプト(LF必須)
*.sh     text eol=lf
*.bash   text eol=lf
*.zsh    text eol=lf
*.fish   text eol=lf
*.csh    text eol=lf
*.ksh    text eol=lf

# Makefile(LF必須)
Makefile  text eol=lf
makefile  text eol=lf
*.mk      text eol=lf
GNUmakefile text eol=lf

# Docker(LF必須)
Dockerfile    text eol=lf
Dockerfile.*  text eol=lf
*.dockerfile  text eol=lf
docker-compose.yml text eol=lf

# CI設定(LF必須)
.travis.yml     text eol=lf
.gitlab-ci.yml  text eol=lf
Jenkinsfile     text eol=lf

# Windowsスクリプト(CRLF必須)
*.bat    text eol=crlf
*.cmd    text eol=crlf
*.ps1    text eol=crlf
*.psm1   text eol=crlf
*.psd1   text eol=crlf

# Gitフック(LF必須)
.husky/* text eol=lf

シバン問題

Unixシステムがcrlf行末のスクリプトを実行しようとすると、シバン行(#!/bin/bash)が#!/bin/bash\rとして解釈されます。カーネルは/bin/bash\r(キャリッジリターン付き)というインタープリターを探しますが、存在しません:

/bin/bash^M: bad interpreter: No such file or directory

このエラーは不可解で、特にCI/CDパイプラインでは開発者が直接ターミナルにアクセスできないため、デバッグが困難です。

DockerとCRLF

Linux上のDockerビルドは、DockerfileまたはエントリポイントスクリプトのシェルコマンドにCRLF行末がある場合に失敗します。一般的な症状:

standard_init_linux.go: exec user process caused "no such file or directory"

Gitフック

Gitフック(.husky/*.git/hooks/*)はGit自体が実行するシェルスクリプトです。LF行末と実行可能パーミッションが必要です。.gitattributesが行末を処理し、chmod +xがパーミッションを処理します。

行末のテスト

行末が正しいことを確認します:

# ファイルのCRLFを確認
file script.sh
# 出力: "script.sh: Bourne-Again shell script, ASCII text executable"
# vs: "script.sh: Bourne-Again shell script, ASCII text executable, with CRLF line terminators"

ユースケース

Unixシェルスクリプトとwindowsバッチ/PowerShellスクリプトの両方を含むリポジトリには、明示的なeolディレクティブが必要です。これは、CI/CDパイプライン、Dockerワークフロー、またはクロスプラットフォーム開発チームを持つプロジェクトにとって重要です。

試してみる — .gitattributes Generator

フルツールを開く