shfmt について
shfmt はシェルスクリプトのフォーマットと解析を行い、一貫したコードスタイルを適用します。POSIX や Bash など複数のシェル方言に対応し、単一ファイルまたはディレクトリ全体のフォーマットに対応します。
主な機能
- 01単一または複数のシェルスクリプトをフォーマットする
- 02一貫したシェルコードスタイルを自動適用する
- 03POSIX、Bash など複数のシェル方言に対応
活用シーン
- 01チーム全体のシェルスクリプトスタイルを統一する
- 02自動ワークフローでスクリプトフォーマットを標準化する
- 03バージョン管理とコード整合性チェックを連携させる
インストール
OS またはパッケージマネージャーを選び、コマンドをターミナルで実行します。
インストール後にshfmt --versionを実行して確認します。
コマンド例
よく使うコマンドを使う順に並べています。
詳細
sh
シェルのパーサー、フォーマッター、インタープリターです。 POSIX Shell、Bash、Zsh、mkshに対応しています。Go 1.26以降が必要です。
クイックスタート
シェルスクリプトを構文木に解析して調査し、
shfmtのようにフォーマットする方法については、
syntax packageを参照してください。
シェルのセマンティクスに対応した、1回の呼び出しで使えるヘルパーについては、
shell packageを参照してください。
コマンドラインを引数に分割してshlexのように引用符で囲み直す、文字列内の$VARや~を展開する、
**でグロブする、またはcase形式のパターンに一致させることができます。
Windowsを含め、システムシェルなしでシェルスクリプトを実行する方法については、 interp packageを参照してください。 そのハンドラーを使って、スクリプトで実行やアクセスを許可する対象を設定できます。
shfmt
go install mvdan.cc/sh/v3/cmd/shfmt@latest
shfmtはシェルプログラムをフォーマットします。デフォルトのスタイルを手早く確認するには、
canonical.shを参照してください。たとえば、次のように実行します。
shfmt -l -w script.sh
詳しくはマニュアルページを参照してください。 Markdownとして直接表示することも、scdocでレンダリングすることもできます。
パッケージはAlpine、Arch、Debian、Docker、Fedora、FreeBSD、 Homebrew、MacPorts、NixOS、OpenSUSE、PyPI、Scoop、Snapcraft、Void、webiで入手できます。
スポンサーになる
このプロジェクトによってあなたやあなたの会社の時間が節約できた場合は、 GitHubで私をスポンサーすることをご検討ください。 月額プランには、READMEへのロゴ掲載、課題の優先対応、会社のチャットアプリでの直接サポートなどの特典があります。 単発プランでは、私のプロジェクトについての相談や、Goのコンサルティングまたはメンタリングを受けられます。
コントリビュート
バグ報告や機能リクエストは、詳細な課題として登録してください。 できれば、バグを再現する例や、希望する機能を示す例を添えてください。
プロジェクトを積極的に利用または開発している方でない限り、突発的なAIパッチは役に立ちません。 代わりに、詳細な課題を登録してください。
注意事項
- Bashの連想配列をインデックス指定する場合は、必ず引用符を使ってください。そうしないと、静的パーサーはインデックスを算術式として扱う必要があると判断します。
$ echo '${array[spaced string]}' | shfmt
<standard input>:1:16: not a valid arithmetic operator: `string`
$ echo '${array[weird!key]}' | shfmt
<standard input>:1:8: reached `!` without matching `[` with `]`
$ echo '${array[dash-string]}' | shfmt
${array[dash - string]}
$((と((の曖昧さには対応していません。バックトラッキングを導入するとパーサーが複雑になり、io.Readerによるストリーミング対応も不可能になるためです。$( (を意図している場合は、POSIX仕様に従ってオペランドの間にスペースを入れてください。
$ echo '$((foo); (bar))' | shfmt
1:1: reached ) without matching $(( with ))
-
export、let、declareはキーワードとして解析されます。 これにより、引数を単語のスライスとして保持する代わりに、 構文木を静的に構築できます。 また、declare foo=(bar)に対応するためにも必要です。 -
ライブラリ全体は純粋なGoで記述されているため、 インタープリターがPOSIX ShellやBashのセマンティクスを厳密に再現するには限界があります。 たとえば、Goでは自身のプロセスをフォークできないため、サブシェルには代わりにゴルーチンを使います。 そのため、実際のPIDやファイル記述子を直接使用できません。
フォーマットに関するよくある質問
-
フォーマッターを指定した行範囲で無効にすることはできません。これを望むユーザーの多くは、 バグを回避しようとしているか、コードの一部のフォーマットが気に入らないだけです。 代わりに課題トラッカーを検索し、必要であれば新しい課題を登録してください。 ファイルの一部だけをフォーマットすると、多くの例外的なケースや複雑さが生じます。 このプロジェクトには、それに取り組むリソースも意欲もありません。
-
可能な限り、フォーマットオプションを追加しないようにしています。フラグを追加するたびに、 他のすべてのフラグとの組み合わせが増え、開発、保守、テスト、エンドユーザー向けの動作説明に必要な労力が増大するためです。
-
フォーマッターの真の価値は一貫性にあり、特に開発者チームにとって重要です。 すべての開発者個人の好みに合わせて最適なフォーマットを提供することを目指しているわけではありません。
JavaScript
パーサーとフォーマッターは、ライブラリのWASMコンパイル版をバンドルしたサードパーティー製npmパッケージ、sh-syntaxで利用できます。
以前は、GopherJSを使ってこのライブラリのJS版をバンドルするnpmパッケージ、mvdan-shをメンテナンスしていました。このnpmパッケージは、パフォーマンスが低く、GopherJSの開発もあまり活発でないため、現在はアーカイブされています。既存ユーザーも新規ユーザーも、代わりにsh-syntaxをご利用ください。
Docker
すべてのリリースタグは、v3.5.1のようにDocker経由で公開されています。
現在、最新の安定版リリースはv3として、最新の開発版はlatestとして公開されています。
イメージにはshfmtのみが含まれます。Alpine Linux用には-alpine版もあります。
Dockerイメージをビルドするには、次を実行します。
docker build -t my:tag -f cmd/shfmt/Dockerfile .
Dockerイメージを使用するには、次を実行します。
docker run --rm -u "$(id -u):$(id -g)" -v "$PWD:/mnt" -w /mnt my:tag <shfmt arguments>
関連プロジェクト
以下のエディター統合は shfmt をラップしています。
- BashSupport-Pro - JetBrains IDE 向けの Bash プラグイン
- dockerfmt - shfmt を使用する Dockerfile フォーマッター
- intellij-shellscript - Intellij Jetbrains の
shell scriptプラグイン - micro - プラグインが組み込まれたエディター
- neoformat - (Neo)Vim プラグイン
- vscode-shfmt - VS Code プラグイン
- shfmt.el - Emacs パッケージ
- Trunk - CLI、VS Code プラグイン、GitHub アクションとして利用できるユニバーサルリンター
その他の注目すべき統合には、以下があります。
- modd - ファイルシステムの変更に応答する開発者向けツール
- prettier-plugin-sh - sh-syntax を使用する Prettier プラグイン
- sh-checker - シェルスクリプトの静的解析を実行する GitHub アクション
- mdformat-shfmt - Markdown に埋め込まれたシェルスクリプトを shfmt でフォーマットする mdformat プラグイン
- pre-commit-shfmt - pre-commit の shfmt フック
- tesh - モック、アサーション、カバレッジを使用してスクリプトを実行