posix-shell-pro について
POSIX シェルスクリプトの作成と保守を支援するガイドスキルです。Unix 系環境での移植性、安全なエラー処理、検証を重視し、テストや Bash からの移行方法も扱います。
主な機能
- 01POSIX 構文と移植性の指針
- 02防御的なエラー処理と入力検証
- 03複数シェルでのテストと静的解析
- 04Bash から POSIX sh への移行指針
活用シーン
- 01複数の Unix シェル向けスクリプトの作成
- 02スクリプト内の Bash 固有構文の確認
- 03組み込み環境向けのスクリプト調整
- 04複数シェルでのテストと検証の計画
インストール
コマンドをコピーしてターミナルで実行します。
$
npx skills add https:/ / github.com/ sickn33/ agentic-awesome-skills --skill posix-shell-proインストール後、Claude Code で/posix-shell-proを入力して読み込まれたか確認します。
詳細
このスキルを使う場面
- posix shell proに関するタスクやワークフローに取り組む場合
- posix shell proのガイダンス、ベストプラクティス、チェックリストが必要な場合
このスキルを使わない場面
- タスクがposix shell proに関係ない場合
- この範囲外の別の分野やツールが必要な場合
指示
- 目標、制約、必要な入力を明確にします。
- 関連するベストプラクティスを適用し、結果を検証します。
- 実行可能な手順と検証方法を提示します。
注力分野
- 最大限の移植性を実現する、厳格なPOSIX準拠
- あらゆるUnix系システムで動作する、シェルに依存しないスクリプト
- 移植性のあるエラー処理による防御的なプログラミング
- bash固有の機能を使わない、安全な引数解析
- 移植性のあるファイル操作とリソース管理
- クロスプラットフォーム互換性(Linux、BSD、Solaris、AIX、macOS)
- dash、ash、およびPOSIXモードでの検証によるテスト
- POSIXモードのShellCheckによる静的解析
- POSIXで規定された機能のみを使う、最小限のアプローチ
- レガシーシステムや組み込み環境との互換性
移植性の目標:ユーザーが明示的にPOSIX.1-2024を選択しない限り、広く普及しているPOSIX.1-2017対応シェルを対象にします。新しい規格の機能は、レガシーシステムでは利用できない場合があります。シェルの規格準拠とユーティリティの利用可否は別々のため、対象ホストの両方でテストしてください。
POSIXの制約
- 配列は使わない(位置パラメーターまたは区切り文字列を使用)
[[条件式は使わない([テストコマンドのみ使用)- プロセス置換
<()または>()は使わない - ブレース展開
{1..10}は使わない localキーワードは使わない(関数スコープの変数を慎重に使用)declareまたはtypesetは使わない。POSIXのreadonly name=valueは使用可能- 文字列連結に
+=演算子は使わない ${var//pattern/replacement}による置換は使わない- 連想配列やハッシュテーブルは使わない
sourceコマンドは使わない(ファイルの読み込みには.を使用)
アプローチ
- POSIXシェルでは常に
#!/bin/shのシバンを使います set -euを検討しつつ、想定される失敗は明示的に確認します。-eには条件式やサブシェルでの例外があります。pipefailはPOSIX.1-2024で標準化されましたが、2017年頃の多くのシェルでは利用できません- 変数展開はすべて引用符で囲みます。
$varではなく、必ず"$var"を使います - すべての条件判定に
[ ]を使い、[[は使いません whileとcaseを使って引数を解析します(長いオプションにはgetoptsを使わない)mktempは、利用可能であることを確認してから使います(POSIX.1-2017のユーティリティではありません)。そうでない場合は、レビュー済みのプラットフォーム固有の安全な一時ディレクトリの方式を必須とします- すべての出力には
echoではなくprintfを使います(echoの動作は環境によって異なります) - ファイルの読み込みには
source script.shではなく. script.shを使います || exit 1を明示してエラーを処理します- スクリプトは冪等にし、ドライランモードに対応させます
IFSの操作は慎重に行い、元の値に戻します[ -n "$var" ]および[ -z "$var" ]のテストで入力を検証します- オプション解析は
--で終了し、安全のためrm -rf -- "$dir"を使います - 可読性を高めるため、バッククォートではなくコマンド置換
$()を使います dateを使い、タイムスタンプ付きの構造化ログを実装します- POSIX準拠を確認するため、スクリプトをdash/ashでテストします
互換性と移植性
- システムのPOSIXシェルを起動するために
#!/bin/shを使います - 複数のシェルでテストします:dash(Debian/Ubuntuのデフォルト)、ash(Alpine/BusyBox)、bash --posix
- GNU固有のオプションは避け、POSIXで規定されたフラグのみを使います
- プラットフォームの違いに対応します。OSの判定には
uname -sを使います - より移植性のある
command -vをwhichの代わりに使います - コマンドが利用可能か確認します:
command -v cmd >/dev/null 2>&1 || exit 1 - ユーティリティが利用できない場合は、移植性のある実装を用意します
- 存在確認には
[ -e "$file" ]を使います(すべてのシステムで動作します) /dev/stdin、/dev/stdoutは、すべての環境で利用できるわけではないため避けます- bash固有の
&>ではなく、明示的なリダイレクトを使います
可読性と保守性
- エクスポートする変数には UPPER_CASE、ローカル変数には lower_case の説明的な名前を使用します
- 整理のため、コメントブロックでセクション見出しを追加します
- 関数は50行未満にし、複雑なロジックは切り出します
- インデントを統一します(スペースのみ。通常は2または4文字分)
- 関数の目的とパラメーターをコメントで説明します
- 意味のある名前を使用します。
checkではなくvalidate_inputのような名前にします - 一見して分かりにくい POSIX の回避策にはコメントを追加します
- 関連する関数を説明的な見出しでグループ化します
- 繰り返し使うコードは関数に切り出します
- 論理的なセクションを空行で区切ります
安全性とセキュリティのパターン
- 単語分割を防ぐため、すべての変数展開を引用符で囲みます
- 操作の前にファイルのアクセス権を検証します:
[ -r "$file" ] || exit 1 - コマンドで使用する前に、ユーザー入力をサニタイズします
- 数値入力を検証します:
case $num in ''|*[!0-9]*) exit 1 ;; esac - 信頼できない入力に
evalを決して使用しません - オプションと引数を分けるには
--を使用します:rm -- "$file" - 必須変数を検証します:
[ -n "$VAR" ] || { echo "VAR required" >&2; exit 1; } - 終了コードを明示的に確認します:
cmd || { echo "failed" >&2; exit 1; } - クリーンアップには
trapを使用します:trap 'rm -f "$tmpfile"' 0; trap 'exit 1' HUP INT TERM - 機密ファイルには制限の厳しい umask を設定します:
umask 077 - セキュリティに関わる操作を syslog またはファイルに記録します
- ファイルパスに想定外の文字が含まれていないことを検証します
- セキュリティが重要なスクリプトでは、コマンドにフルパスを使用します:
rmではなく/bin/rm
パフォーマンスの最適化
- 可能な場合は外部コマンドよりシェル組み込みコマンドを使用します
- ループ内でサブシェルを起動しないようにします:
for i in $(cat)ではなくwhile readを使用します - コマンドを繰り返し実行する代わりに、結果を変数にキャッシュします
- 複数の文字列を比較する場合は
caseを使用します(繰り返しifを使うより高速です) - 大きなファイルは1行ずつ処理します
- 算術演算には
exprまたは$(( ))を使用します(POSIX は$(( ))をサポートします) - 処理頻度の高いループ内で外部コマンドの呼び出しを最小限に抑えます
- 真偽値だけが必要な場合は
grep -qを使用します(出力を取得するより高速です) - 類似した操作をまとめて実行します
- 複数行の文字列には、複数の echo 呼び出しの代わりにヒアドキュメントを使用します
ドキュメントの基準
- ヘルプ用に
-hフラグを実装します(適切に解析せず--helpを使うのは避けます) - 概要とオプションを示す使用方法のメッセージを含めます
- 必須引数と省略可能な引数を明確に説明します
- 終了コードを列挙します:0=成功、1=エラー、特定の失敗には個別のコード
- 前提条件と必要なコマンドを説明します
- スクリプトの目的と作成者を記載したヘッダーコメントを追加します
- よくある使用パターンの例を含めます
- スクリプトで使用する環境変数を説明します
- よくある問題のトラブルシューティング方法を記載します
- ドキュメントで POSIX 準拠について記載します
配列を使わない場合
POSIX sh には配列がないため、次のパターンを使用します。
- 位置パラメーター:
set -- item1 item2 item3; for arg; do echo "$arg"; done - 区切り文字付き文字列:位置パラメーターを優先します。意図的に分割する場合は、パス名展開を無効にし、元の IFS(未設定の状態も含む)を保持して復元し、空フィールドの扱いを定義します。IFS を無条件に半角スペース1文字へリセットしないでください
- 改行区切り:
while IFS= read -r item || [ -n "$item" ]; do printf '%s\n' "$item"; done < "$input_file"を使用します。引用符で囲んだ"a\nb"に含まれるのは改行ではなく、文字としてのバックスラッシュです - カウンター:
i=0; while [ $i -lt 10 ]; do i=$((i+1)); done - フィールド分割:文字列の分割には
cut、awk、またはパラメーター展開を使用します
移植可能な条件式
POSIX の演算子を使用する [ ] テストコマンドを使用します。
- ファイルテスト:
[ -e file ]は存在、[ -f file ]は通常のファイル、[ -d dir ]はディレクトリ - 文字列テスト:
[ -z "$str" ]は空、[ -n "$str" ]は空でない、[ "$a" = "$b" ]は等しい - 数値テスト:
[ "$a" -eq "$b" ]は等しい、[ "$a" -lt "$b" ]は小さい - 論理演算:
[ cond1 ] && [ cond2 ]は AND、[ cond1 ] || [ cond2 ]は OR - 否定:
[ ! -f file ]は通常のファイルではない - パターンマッチング:
[[ =~ ]]ではなくcaseを使用します
CI/CD 統合
- マトリックステスト:Linux、macOS、Alpine で dash、ash、bash --posix、yash をテストします
- コンテナテスト:再現可能な ash/dash テストのため、レビュー済みの Alpine/Debian イメージダイジェストを固定します。可変タグは移動します
- プリコミットフック:checkbashisms、shellcheck -s sh、shfmt -ln posix を設定します
- GitHub Actions:POSIX モードで shellcheck-problem-matchers を使用します
- クロスプラットフォーム検証:Linux、macOS、FreeBSD、NetBSD でテストします
- BusyBox テスト:組み込みシステム向けに BusyBox 環境で検証します
- 自動リリース:バージョンにタグを付け、ポータブルな配布パッケージを生成します
- カバレッジの追跡:すべての POSIX シェルを対象にテストカバレッジを確保します
- ワークフローの例:
shellcheck -s sh *.sh && shfmt -ln posix -d *.sh && checkbashisms *.sh
組み込みシステムと制限のある環境
- BusyBox 互換性:機能が限られた BusyBox の ash 実装でテストします
- Alpine Linux:デフォルトのシェルは bash ではなく BusyBox ash です
- リソースの制約:メモリ使用量を最小限に抑え、過剰なプロセスの起動を避けます
- ユーティリティの不足:一般的なツール(
mktemp、seq)を利用できない場合は代替手段を用意します - 読み取り専用ファイルシステム:
/tmpが制限されている可能性のある状況に対応します - coreutils がない環境:GNU coreutils の拡張機能を利用できない環境もあります
- シグナル処理:最小構成の環境では、シグナルのサポートが限られています
- 起動スクリプト:最大限の互換性を確保するため、初期化スクリプトは POSIX 準拠にする必要があります
- 例:mktemp の有無を確認します:
command -v mktemp >/dev/null 2>&1 || mktemp() { ... }
Bash から POSIX sh への移行
- 評価:
checkbashismsを実行し、bash 固有の構文を特定します - 配列の排除:配列を区切り文字列または位置パラメーターに変換します
- 条件式の更新:
[[を[に置き換え、正規表現をcaseパターンに変更します - ローカル変数:
localキーワードを削除し、代わりに関数名の接頭辞を使用します - プロセス置換:
<()を一時ファイルまたはパイプに置き換えます - パラメーター展開:複雑な文字列操作には
sed/awkを使用します - テスト戦略:継続的に検証しながら段階的に変換します
- ドキュメント:POSIX の制限や回避策を記載します
- 段階的な移行:一度に 1 つの関数を変換し、十分にテストします
- フォールバックサポート:必要に応じて、移行期間中は 2 つの実装を維持します
品質チェックリスト
- スクリプトが
-s shフラグ(POSIX モード)で ShellCheck を通過する - コードが
-ln posixを使用した shfmt で一貫してフォーマットされている - 複数のシェル(dash、ash、bash --posix、yash)でテストされている
- すべての変数展開が適切に引用符で囲まれている
- bash 固有の機能(配列、
[[、localなど)を使用していない - すべての失敗ケースを対象にエラー処理が行われている
- EXIT トラップで一時リソースがクリーンアップされる
- スクリプトに明確な使用方法が記載されている
- 入力検証によってインジェクション攻撃を防止している
- スクリプトが Unix 系システム(Linux、BSD、Solaris、macOS、Alpine)でポータブルに動作する
- 組み込み用途で BusyBox との互換性が検証されている
- GNU 固有の拡張機能やフラグを使用していない
成果物
- ポータビリティを最大限に高めた POSIX 準拠のシェルスクリプト
- dash、ash、yash での動作を検証する、shellspec または bats-core を使用したテストスイート
- 複数のシェルを対象としたマトリックステスト用 CI/CD 設定
- フォールバックを備えた一般的なパターンのポータブルな実装
- POSIX の制限や回避策を例とともに説明するドキュメント
- bash スクリプトを段階的に POSIX sh に変換するための移行ガイド
- クロスプラットフォーム互換性マトリックス(Linux、BSD、macOS、Solaris、Alpine)
- 各種 POSIX シェルを比較するパフォーマンスベンチマーク
- ユーティリティ(mktemp、seq、timeout)がない場合のフォールバック実装
- 組み込み環境やコンテナ環境向けの BusyBox 互換スクリプト
- bash に依存しない、各種プラットフォーム向けのパッケージ配布物
必須ツール
静的解析とフォーマット
- ShellCheck:POSIX モードの検証に
-s shを使用する静的解析ツール - shfmt:POSIX 構文に対応した
-ln posixオプションを備えるシェルフォーマッター - checkbashisms:スクリプト内の Bash 固有の構文を検出します(devscripts に含まれています)
- Semgrep:POSIX 固有のセキュリティルールに対応した SAST
- シェル解析のカバレッジ:解析ツールが実際にシェルをサポートしていることを確認してください。CodeQL がシェルをカバーすると、デフォルトで主張しないでください
テスト用の POSIX シェル実装
- dash:Debian Almquist Shell。軽量で、POSIX 準拠が厳格です(主なテスト対象)
- ash:Almquist Shell。BusyBox のデフォルトで、組み込みシステム向けです
- yash:Yet Another Shell。POSIX 準拠の厳格な検証に使えます
- posh:Policy-compliant Ordinary Shell。Debian ポリシーに準拠しています
- osh:Oil Shell。エラーメッセージがより分かりやすい、最新の POSIX 互換シェルです
- bash --posix:互換性テスト用の POSIX モードで動作する GNU Bash
テストフレームワーク
- bats-core:POSIX sh でも動作する Bash テストフレームワーク
- shellspec:POSIX sh をサポートする BDD スタイルのテストフレームワーク
- shunit2:POSIX sh をサポートする xUnit スタイルのフレームワーク
- sharness:Git が使用するテストフレームワーク(POSIX 互換)
よくある落とし穴
[の代わりに[[を使用する(Bash 固有)- 配列を使用する(POSIX sh にはありません)
localキーワードを使用する(Bash/ksh の拡張機能)printfの代わりにechoを使用する(動作は実装によって異なります)- スクリプトを読み込む際に
.ではなくsourceを使用する - Bash 固有のパラメーター展開を使用する:
${var//pattern/replacement} - プロセス置換
<()または>()を使用する functionキーワードを使用する(ksh/Bash の構文)$RANDOM変数を使用する(POSIX にはありません)- 配列に
read -aを使用する(Bash 固有) - 旧式の POSIX.1-2017 シェルでも
set -o pipefailが使えると想定する - リダイレクトに
&>を使用する(>file 2>&1を使用してください)
高度なテクニック
- 終了時のクリーンアップ:
trap 'cleanup' 0を使用します。クリーンアップに失敗する可能性がある場合は、元の終了ステータスを保持してください。$LINENOや、常にエラーを出力する終了トラップは、移植性のあるエラー検出方法ではありません - 安全な一時ファイル:
tmpfile=$(mktemp) || exit 1; trap 'rm -f "$tmpfile"' EXIT INT TERM - 配列のシミュレーション:
set -- item1 item2 item3; for arg; do process "$arg"; done - フィールドの解析:
IFS=:; while read -r user pass uid gid; do ...; done < /etc/passwd - 文字列の置換:
echo "$str" | sed 's/old/new/g'を使用するか、パラメーター展開${str%suffix}を使用します - デフォルト値:
value=${var:-default}は、var が未設定または空の場合にデフォルト値を代入します - 移植性のある関数:
functionキーワードは避け、func_name() { ... }を使用します - サブシェルによる分離:
(cd dir && cmd)は、親シェルに影響を与えずにディレクトリを変更します - ヒアドキュメント:
cat <<'EOF'のように引用符で囲むと、変数展開を防げます - コマンドの存在確認:
command -v cmd >/dev/null 2>&1 && echo "found" || echo "missing"
POSIX 固有のベストプラクティス
- 変数展開は必ず引用符で囲みます:
$varではなく"$var" - 適切なスペースを入れて
[ ]を使用します:["$a"="$b"]ではなく[ "$a" = "$b" ] - 文字列の比較には
==(Bash 拡張機能)ではなく=を使用します - スクリプトの読み込みには
sourceではなく.を使用します - すべての出力に
printfを使用し、echo -eやecho -nは避けます - 算術演算には
letやdeclare -iではなく$(( ))を使用します - パターンマッチングには
[[ =~ ]]ではなくcaseを使用します - 構文を確認するには、
sh -n script.shでスクリプトをテストします - 移植性のために、
typeやwhichではなくcommand -vを使用します || exit 1を使い、すべてのエラー条件を明示的に処理します
参考資料と詳細情報
POSIX 標準と仕様
- POSIX Shell Command Language - この URL にある POSIX.1-2017 の公式仕様
- POSIX Utilities - POSIX で必須とされるユーティリティの全一覧
- Autoconf Portable Shell Programming - GNU による包括的な移植性ガイド
移植性とベストプラクティス
- Rich's sh (POSIX shell) tricks - 高度な POSIX シェルのテクニック
- Suckless Shell Style Guide - ミニマルな POSIX sh のパターン
- FreeBSD Porter's Handbook - Shell - BSD の移植性に関する考慮事項
ツールとテスト
- checkbashisms - bash 固有の構文を検出します
例
ユーザーのリクエスト:
このタスクでは @posix-shell-pro を使用してください。Unix 系システム全般で最大限の移植性を実現するための、厳格な POSIX sh スクリプトのエキスパートです。
制限事項
- タスクが上記の説明の範囲に明確に該当する場合にのみ、このスキルを使用してください。
- 出力を、環境固有の検証、テスト、または専門家によるレビューの代わりとして扱わないでください。
- 必要な入力、権限、安全上の境界、または成功基準が不足している場合は、作業を中断して確認を求めてください。
コメント
Markdown 対応