bash-shortening について
読みやすさを保ちながらBashスクリプトを短縮するスキルです。分類別のリファレンス、読み取り専用の分析、特定パターン向けのPythonリライターを備え、既存コードの見直しに使えます。
主な機能
- 019カテゴリにわたってスクリプトを分析
- 02Pythonスクリプトで特定パターンを変換
- 03統一差分で変更をプレビュー
- 04bash -nとshellcheckで編集を検証
活用シーン
- 01Bashスクリプトの短縮候補を調べる
- 02スクリプトに自動変換を適用
- 03短縮で意図が伝わりにくくなる箇所を特定
インストール
コマンドをコピーしてターミナルで実行します。
npx skills add https:/ / github.com/ paulnsorensen/ skillz-that-grillz --skill bash-shorteningインストール後、Claude Code で/bash-shorteningを入力して読み込まれたか確認します。
同梱ファイル
SKILL.md と一緒にインストールされる参考資料やスクリプト。
AGENTS.mdevals/evals.jsonreferences/advanced.mdanti-patterns.mdarithmetic.mdbrace-expansion.mdcommand-substitution.mdfunctions.mdparameter-expansion.mdprocess-substitution.mdreal-world.mdscripts/bash-shorten.pyengine.pyrules.pysgconfig.ymlscripts/sg-rules/backticks.ymltest-numeric-eq.ymltest-numeric-ge.ymltest-numeric-gt.ymltest-numeric-le.ymltest-numeric-lt.ymltest-numeric-ne.yml詳細
bash-shortening
読みやすさを損なわずに Bash スクリプトを短くします。出典:Karandeep Singh の記事「Bash Code Shortening」にある 51 のテクニックを体系化し、チートシートとカテゴリ別のリファレンスにまとめています。
哲学
短縮の目的は、キー入力を減らすことではなく、意図を表現することです。効果があるのは、動く部品(サブプロセス、一時ファイル、中間変数)を減らすことです。1 行のパイプラインで済むのに、一時ファイルを作成して削除する 7 行のスクリプトを書くより、 ${1:-${X:-${Y/-,/ }}} のような解読しにくい連鎖を書くより、明確な 3 行にするほうが優れています。
判断には、次の 2 つの経験則を使います。
- 短縮によって、ある種類のバグをなくせますか?(例:一時ファイルの
rm忘れ、ネストしたifでの分岐漏れ、mkdir -p前のディレクトリ確認における競合)。そうであれば、短縮します。 - 短縮によって、次の読み手に意図が伝わりにくくなりますか? そうであれば、展開します。
両方の経験則に当てはまる場合もあります。相反するときは、明確さを優先してください。詳しくは、長文版の references/anti-patterns.md を参照してください。
このスキルの使い方
アーキテクチャ:ワーカーが調査し、メインスレッドが書き込みます。 読み取り専用のアナライザーワーカーを並列実行して、違反を収集します。その後、メインスレッドが唯一の書き込み担当となり、スクリプトを実行して結果を検証し、残りを手作業で編集します。これにより、同じファイルへの並列書き込み(ユーザーが懸念するのはもっともな、更新の消失を招く競合)を避けられます。
- 対象を特定します。 ファイルパス、貼り付けられたスニペット、または
bashのコードフェンスで囲まれたブロックを指定します。実際に Bash であることを確認してください(「このスキルを使わない場合」を参照)。 - アナライザーによる一斉チェックを実行します。 参照カテゴリごとに読み取り専用のアナライザーワーカーを 1 つずつ、1 回のバッチ呼び出しで起動し、並行して実行します。アナライザーは違反を報告するだけで、書き込み、スクリプトの実行、対象へのアクセスは行いません。以下の「並列チェック — ワーカーの契約」を参照してください。
- アナライザーのレポートを統合します。 各アナライザーの
path:line — 冗長な記述 → 慣用的な記述という指摘を収集します。重複は整理します(同じ行が 2 つのカテゴリで指摘されることがあります。その場合は 1 つにまとめ、両方のカテゴリを記載してください)。 - メインスレッドからスクリプトを実行します。
python3 scripts/bash-shorten.py --apply <target>を実行します(1 回の呼び出しにつき 1 ファイル。複数ある場合は、リストをループ処理します)。これにより、信頼性の高いcoreルールを 1 人の書き込み担当者が適用します。--applyをワーカーに任せてはいけません。 - スクリプトの出力を検証します。 構文チェックには
bash -n <target>を、利用可能であればshellcheck <target>を実行し、差分を確認します。ルールの出力に意図しないものがあれば元に戻し、--rulesまたは--skipで対象を絞ってから再試行してください。 - 残りの対応項目を提示します。 スクリプトで処理されなかったアナライザーの指摘を示し、特にアンチパターンの指摘と短縮の指摘が衝突する場合は、適用するカテゴリをユーザーに選んでもらいます。
- 残りを手作業で編集します。 各変更は、根拠がわかるように 1 つのテクニックずつ適用します。該当するリファレンスファイルの
before / afterの例を使ってください。引用符("$var")、set -euo pipefail、エラー処理は維持します。何をするのかを説明するコメントが必要になるような書き換えは避けてください。
大量の書き換えを黙って行ってはいけません。ワーカーが調査し、メインスレッドが書き込みます。すべての変更は、ユーザーが学べるよう、1 つのテクニックに結び付けます。
自動書き換え
このスキルには、確度の高いパターンに対応する Python リライター scripts/bash-shorten.py が含まれています。サードパーティ製の Python 依存関係はありませんが、PATH 上に ast-grep(sg)が必要です。詳しくは、下記の「ast-grep が必要です」セクションをご覧ください。デフォルトではドライランを実行し(統合差分を標準出力に、ルールごとの件数を標準エラー出力に表示します)、--apply を指定した場合にのみ書き込みます。実行後は必ず出力に対して shellcheck を実行してください。
# preview rewrites
python3 scripts/bash-shorten.py path/to/script.sh
# apply (atomic write, preserves the file in place)
python3 scripts/bash-shorten.py --apply path/to/script.sh
# only run a subset of rules
python3 scripts/bash-shorten.py --rules backticks,test-numeric script.sh
# disable a rule
python3 scripts/bash-shorten.py --skip find-exec-rm-delete script.sh
# enable the modernize rule group (off by default — see "Rule groups")
python3 scripts/bash-shorten.py --include modernize --apply script.sh
# explore the ruleset
python3 scripts/bash-shorten.py --list
python3 scripts/bash-shorten.py --explain test-numeric
# verify the rules still work after editing
python3 scripts/bash-shorten.py --self-test
**2 つのルールグループ(core、modernize)**があり、各ルールには正例と負例のフィクスチャが組み込まれています(現在の件数を確認するには --list を実行してください)。core グループはデフォルトで有効で、modernize グループはオプトインです。core のルールの大半は、元記事の例(sed-replace-first/all、echo-wc-c、cut-c-substring、expr-arith-vars/literal/increment、combined-tests、test-numeric、empty-default、param-default、mkdir-guard、for-range-expansion)に対応しています。残りは記事では扱っていないものの、明らかに効果がある追加の core パターン(backticks、legacy-null-check、empty-string-eq、find-exec-rm-delete、cat-file-pipe-grep)です。このうち 3 つは shellcheck が警告しますが、自動修正はしません。
リライターが意図的に対応していないこと:データフロー解析が必要な処理(1 回しか使われない変数のインライン化)、複数ステートメントの検出(一時ファイルからパイプラインへの置き換え)、関数の抽出、並列化、動作に関する判断(「この &&/|| チェーンは安全か?」)などです。これらは参考資料をもとに手作業で編集してください。
ユーザーから「このスクリプト全体を短くできますか?」と尋ねられた場合、メインスレッドは読み取り専用のアナライザーによる一括スキャンが終わってから、スクリプトを実行します(次のセクションを参照)。スクリプトが面倒な書き換えの 60% を処理し、アナライザーが正規表現では見つけられない箇所をカバーします。書き込みを行うのはメインスレッドだけです。
並列スキャン — ワーカーの契約
コンテキスト内のレビュー担当者が 1 人だけだと、最初に確認した 1、2 個のカテゴリに視野が偏り、コマンド置換、パラメーター展開、算術、ブレース展開、プロセス置換、関数、高度な項目、実例といった分野を見落としがちです。これを防ぐため、参考資料のカテゴリごとに 1 つずつ、読み取り専用のアナライザーを並列で実行します。違反を収集するだけで、書き込みは行いません。その後、メインスレッドがスクリプトを実行し、手作業で編集します。
ワーカーは厳密に読み取り専用です
すべての並列ワーカーに同じ契約が適用されます。**対象を読み、違反を報告して、終了する。**ディスクへの書き込み、書き換えの適用、scripts/bash-shorten.py --apply の実行は、どのワーカーも行いません。書き込みを伴う作業はワーカーの仕事ではなく、メインスレッドの仕事です。
理由:同じファイルへの並列書き込みは競合します。各ワーカーをそれぞれのカテゴリに限定しても、共有する行に重複する差分が生じ、メインスレッドが手作業でマージする必要があります。まず収集し、書き込みは 1 回だけ行います。
ワーカーの種類
| ワーカー | 数 | 役割 | 出力 |
|---|---|---|---|
| カテゴリアナライザー | 参考資料のカテゴリごとに 1 つ(デフォルトで 9 つ) | references/<category>.md を読み、対象内で対応するパターンをスキャンする | 書き換えを行わず、path:line — 冗長な形式 → 慣用的な形式 の Markdown リスト |
各カテゴリアナライザーへの指示(<category> と <target> を置き換えてください。このスキル内のパスは、特記がない限りスキルディレクトリからの相対パスです。短縮するスクリプトのリポジトリ相対パスを <target> として渡してください):
references/<category>.md(bash-shortening スキルディレクトリからの相対パス)を読みます。対応するパターンをすべて対象の<target>から探してください。結果はpath:line — 冗長な形式 → 慣用的な形式の Markdown リストで返してください。ファイルを書き換えず、scripts/bash-shorten.pyも実行せず、何も書き込まないでください。該当箇所がアンチパターンの参考資料に抵触する場合は、その旨を示したうえでリストに含めてください。
**ディスパッチ規則:**すべてのアナライザーを 1 回のバッチ呼び出しで起動し、並行して実行してください。順番に起動すると、並列化の最大の利点である待ち時間の短縮が損なわれます。
ハーネスに依存しない — 使用するプリミティブを選ぶ
契約は「読み取り専用タスクを N 件並列に実行し、結果を収集する」です。 ハーネスが提供するプリミティブを使用してください。このスキルは 特定のプリミティブに依存しません。
- 並列サブエージェント/サブタスク呼び出し(ワーカーをすべて同時に起動する、1 回のバッチメッセージ)。
- 1 回のアシスタントターンで複数のツール呼び出しを並列実行する。
- エージェントグラフフレームワークでのタスク/ノードのファンアウト。
- 通常のシェル:ワーカーの指示をエージェント CLI にパイプで渡して、
xargs -P 9またはparallelを実行し、各ワーカーの標準出力を別々のファイルに保存する。 - 並列プリミティブが使えない場合: カテゴリテーブルを 1 回で順番に確認します。それぞれを明示的にチェックしてください。最初に見つかったものだけに視野が狭まることを防ぐために、このセクションがあります。
カテゴリ
以下は完全なチェックリストです。2、3 個のカテゴリで該当箇所を見つけても、そこで止めないでください。basename/dirname/for-range だけに視野が狭まり、コマンド置換、パラメーター展開、算術演算、ブレース展開、プロセス置換、関数、advanced、real-world を見落とすことを防ぐために、このセクションがあります。
| カテゴリ | リファレンス | 記事の参照先 | 検出するパターン |
|---|---|---|---|
| コマンド置換の一括確認 | references/command-substitution.md | 3-7 | $(cmd) による一時ファイルの排除、パイプラインと再利用される出力の比較、xargs のパターン、find … | xargs とプロセス置換の比較 |
| パラメーター展開の一括確認 | references/parameter-expansion.md | 8-15 | if [ -z "$X" ]; then X=… 形式のデフォルト値、cut -c/echo | sed による置換、${#S} による長さの取得、basename/dirname を使うシェル |
| 関数パターンの一括確認 | references/functions.md | 16-20 | 繰り返されるロギングブロック、デフォルトパラメーターの定型コード、echo による戻り値、名前付きパラメーターのパターン |
| ブレース展開の一括確認 | references/brace-expansion.md | 21-26 | mkdir/touch a b c の逐次実行、for i in 1 2 3 4 5 形式の範囲、ゼロ埋めした連番 |
| プロセス置換の一括確認 | references/process-substitution.md | 27-31 | diff/ループに渡す一時ファイル、echo "x" | cmd から <<< のヒアストリングへの置き換え |
| 算術演算の一括確認 | references/arithmetic.md | 32-38 | expr、$(…)+1 によるインクリメント、[ -gt/-lt/-eq ] による数値比較、[ "$A" ] && [ "$B" ] |
| 実例の一括確認 | references/real-world.md | 39-45 | 設定の解析、ログ分析、ヘルスチェック、バッチ処理、バックアップ、API と jq |
| 高度なパターンの一括確認 | references/advanced.md | 48-51 | 繰り返される echo 行(→ ヒアドキュメント)、3 つ以上の分岐を持つ if/elif(→ 連想配列または case)、独立したコマンドの逐次実行(→ & … & wait)、ループ内の cut -d,(→ 独自の IFS) |
| アンチパターンの一括確認 | references/anti-patterns.md | 1-2, 46-47 | 入れ子の展開、解読しにくいワンライナー、短縮すると逆効果になる箇所 — ユーザーに指摘し、自動で書き換えないでください |
マージ、適用、検証 — 書き込み担当は1つ
すべてのアナライザーが結果を返した後、メインスレッドがすべての書き込みを担当します。
- カテゴリごとの該当箇所リストを収集して重複を除去します。同じ行が2つのアナライザーで検出される場合があります。その場合は1つの項目として残し、両方の検出元を記録します。
- メインスレッドから書き換えスクリプトを実行します。ファイルごとに
python3 scripts/bash-shorten.py --apply <target>を1回実行します(複数ファイルがある場合はループします。スクリプトが受け取る位置引数は1つのファイルです)。デフォルトはcoreです。sd/rg/fd の書き換えを対象にするには、--include modernizeを追加します。--applyを実行するのはここだけです。 - スクリプトの出力を検証します。構文を確認するには
bash -n <target>を実行し、利用可能であればshellcheck <target>も実行して、差分を手動で確認します。ルールによる変更が予想外の場合は、元に戻し、--rulesまたは--skipで対象を絞ってから再試行します。 - スクリプトで対応できなかった検出箇所をまとめた、残りのアナライザーの対応リストを提示します。特に、アンチパターンの検出箇所と短縮の検出箇所が競合する場合は、適用するカテゴリをユーザーに選んでもらいます。
- それぞれの変更に理由を添え、「このスキルの使い方」のワークフローに従って、手動編集を1つの手法ごとに適用します。各編集はメインスレッドからの単一の書き込みとし、処理の分散や並列化は行いません。
書き込み担当を1つにする理由: アナライザーは「何を探すか」という点では互いに独立していますが、提案する書き換えは同じ行で重複します(for i in 1 2 3 4 5 の検出箇所は、ブレース展開と算術演算の両方、場合によっては実例のカテゴリにも現れます)。ワーカーが並列で書き込むと、後から書き込んだワーカーが他の変更を気付かれないまま上書きしてしまいます。すべての違反を先に集め、1か所から適用することで、差分を監査しやすくし、更新の消失を防げます。
分析を分散する理由: 各カテゴリは互いに独立しており、作業中にそれぞれ異なる参照ファイルを必要とします。また、ワーカーを並列化することで、多数のファイルを1回確認するだけでは見落としがちな箇所も確実にカバーできます。読み取り専用のタスクは競合しないため、ここでは並列化のコストはありません。まさに、書き込み担当を1つにする規律が適用されない場面です。
ルールグループ
| グループ | デフォルト | 内容 |
|---|---|---|
core | オン | ツールを変更しない、18種類の慣用的な Bash 書き換え |
modernize | オフ | sed-replace-to-sd、grep-fixed-to-rg、find-name-to-fd — ユーザーがインストールしておく必要のある coreutils 以外のバイナリ(sd、rg、fd)を使うように書き換えます |
modernize ルールは意図的に保守的です。sd に対応するのはリテラルの sed パターンだけです。rg -F に対応するのは grep -F(固定文字列)だけです(通常の grep PAT は BRE を使います。これは rg の正規表現の仕様と十分に異なるため、動作が気付かれないまま変わるリスクがあります)。また、追加のフラグを含まない find . -type f -name "GLOB" だけが fd に対応します(それでも find → fd の書き換えによって動作が変わります。fd はデフォルトで .gitignore を尊重します)。
--include modernize でオプトインします。インストーラー(scripts/install.sh)は sd、ripgrep、fd、ast-grep をインストールするため、書き換え後のコードが実行でき、書き換えツールが必要とする依存関係もそろいます。
ast-grep が必要です
bash-shorten.py の実行には、PATH 上に ast-grep(sg)が必要です。構造パターン(backticks、test-numeric)は、まず scripts/sg-rules/ のルールパックを使って ast-grep に通し、その後、残りの正規表現ルールを出力に適用します。bash は Tree-sitter で一度だけ解析するため、コンテキスト依存のルール(# コメントやヒアドキュメントの本文をスキップする処理)が、正規表現レイヤーで場当たり的な後読みを使わなくても正しく動作します。
sg が見つからない場合、スクリプトは分かりやすい診断メッセージを表示して終了します。先に進む方法は 2 つあります。
brew install ast-grep # macOS / Linuxbrew
cargo install ast-grep --bin sg
または、スクリプトは使わず、並列スイープからカテゴリ別アナライザーのみを実行します。このファイルに記載されている参照ベースの方法は、ast-grep を利用できない環境向けの代替手段です。
一部のルールが正規表現のみで実装されている理由。
mkdir-guard、empty-default、param-default、expr-incrementでは、メタ変数をまたいだ一致(2 か所で同じ名前を使うこと)が必要です。YAML の ast-grep ルールではこの制約を簡潔に表現できないため、Python の正規表現で後方参照を使っています。combined-tests—[ ... ]は単語トークンのリストに平坦化されるため、演算子側の構造マッチングは不安定です。for-range-expansion— キャプチャした整数がステップ 1 で昇順に並ぶかを確認するには、実行時の算術処理が必要です。YAML のみのルールでは計算できません。sed-replace-*— リテラルパターンのガードには、マッチャーで文字クラスの制限が必要です。
test-numeric は以前この一覧に含まれていましたが、sg-rules/ に演算子ごとの 6 つのルールとして移されました。tree-sitter-bash は test_command([ ])と conditional_expression([[ ]])を区別するため、sg 形式では [[ ]] を正しくスキップできますが、正規表現では対象に含まれてしまっていました(issue #18)。
これらの正規表現のみのルールは、引き続き ast-grep の処理後に実行されます。新しいルールの作成方法については AGENTS.md を参照してください。原則として ast-grep を使い、上記の制約に該当する場合に限り正規表現を使用してください。
すぐに使える改善例
よくある肥大化パターンと、詳しい説明の参照先です。 括弧内の数字は、元の記事の例番号です。
| 冗長な形式 | 慣用的な形式 | 参照先 |
|---|---|---|
if [ -z "$X" ]; then X=default; fi | X=${X:-default} | parameter-expansion (8) |
$(echo "$S" | cut -c1-5) | ${S:0:5} | parameter-expansion (10) |
$(basename "$P") / $(dirname "$P") | ${P##*/} / ${P%/*} (手動編集のみ。末尾にスラッシュがあるパスでは警告なしに動作が壊れます。また、パスに / がない場合、dirname の結果は ${P%/*} と異なります(本来の dirname は . を返しますが、展開では元の文字列が返ります)。リライターでは自動適用されません) | parameter-expansion (11-12) |
$(echo "$S" | sed 's/a/b/g') | ${S//a/b} | parameter-expansion (13-14) |
$(echo -n "$S" | wc -c) | ${#S} | parameter-expansion (15) |
$(expr $A + $B) / C=$(expr $C + 1) | $((A + B)) / ((C+=1))(または C=$((C + 1))) | arithmetic (32-34) |
[ $X -gt 100 ] / [ $A ] && [ $B ] | ((X > 100)) / [[ $A && $B ]] | arithmetic (35, 37) |
mkdir a; mkdir b; mkdir c | mkdir -p {a,b,c} | brace-expansion (21-22) |
for i in 1 2 3 4 5 | for i in {1..5}(または {01..10}、{2..10..2}) | brace-expansion (23-26) |
cmd > /tmp/x; cmd2 < /tmp/x; rm /tmp/x | cmd | cmd2 または cmd2 < <(cmd) | command-substitution (5)、process-substitution (29) |
sort a > /tmp/a; sort b > /tmp/b; diff ... | diff <(sort a) <(sort b) | process-substitution (27) |
if [ "$E" = dev ]; elif ... ; fi(分岐が3つ以上) | case または 連想配列 ${URLS[$E]:-default} | functions (intro)、advanced (49) |
echo "[$(date)] [LEVEL] msg" の繰り返し | ${1^^} を使う log() 関数 | functions (16) |
find ... > /tmp/x; while read; ...; done < /tmp/x; rm | find ... | xargs cmd または done < <(find ...) | command-substitution (6)、process-substitution (29) |
複数行の echo "..." を N 回 | cat <<EOF ... EOF のヒアドキュメント | advanced (48) |
cmd1; cmd2; cmd3(順次実行、相互に独立) | cmd1 & cmd2 & cmd3 & wait | advanced (50) |
ループ内の cut -d, -f1,2,3 | while IFS=, read -r a b c | advanced (51) |
ユーザーのパターンがここにない場合は、以下の参照インデックスを検索してください。 記事の例はすべてそのまま掲載されています。
参照インデックス
手法の種類に合ったファイルを読んでください。各ファイルには、元の記事の変更前と変更後の例、および把握しておくべき注意点がすべて記載されています。
| ファイル | 内容 | 例 |
|---|---|---|
references/command-substitution.md | パイプライン、xargs、一時ファイルの削除、コマンド出力の一度だけの使用と再利用 | 3-7 |
references/parameter-expansion.md | デフォルト値、代替値、部分文字列、パスの抽出、置換、長さ | 8-15 |
references/functions.md | ログ出力、デフォルト引数、インライン条件分岐、戻り値としての echo、名前付き引数 | 16-20 |
references/brace-expansion.md | ディレクトリ/ファイルの展開、数値と文字の連続、刻み幅、ゼロ埋め | 21-26 |
references/process-substitution.md | <(cmd)、>(cmd)、ヒアストリング(<<<)、コマンドからループへの入力 | 27-31 |
references/arithmetic.md | $(( ))、(( ))、[[ ]]、比較演算子、三項演算子に関する注意点 | 32-38 |
references/real-world.md | 設定の解析、ログ分析、ヘルスチェック、バッチ処理、バックアップ、ユーザー管理、APIとjq | 39-45 |
references/anti-patterns.md | 短縮すべきでない場合 — 読みにくいワンライナー、入れ子の展開、基本理念 | 1-2, 46-47 |
references/advanced.md | ヒアドキュメント、連想配列、並列実行と wait、CSV 用のカスタム IFS | 48-51 |
このスキルを使用しない場合
- bash 以外のシェル。 ほとんどのパラメーター展開(
${var//x/y}、${var:offset:length})、[[ ]]、配列、プロセス置換は bash 固有の機能です。スクリプトのシバンが#!/bin/sh、#!/usr/bin/env dash、 またはposh/Alpine のash/busybox を対象としている場合は、 レジスターを切り替えるか、理由を説明して対応を断ってください。fishとzshにはそれぞれ独自の文法があり、これらの内容は適用されません。 - ワンライナーの短縮。 ユーザーがコードゴルフの課題向けに明示的に 最短の行を求めている場合、読みやすさを損なってでも短くすることが目標であり、 問題ではありません。ただし、読みやすさが損なわれることを伝え、 選択の責任はユーザーに委ねてください。
- 重要なインフラストラクチャのスクリプト。 起動スクリプト、初期化スクリプト、 ログの設定前に実行されるスクリプトは、無難であることが大切です。 インシデント発生時の午前 3 時に実行されるコードでは、 洗練さと引き換えに明瞭さを犠牲にしないでください。
- POSIX 互換性の要件。 ディストリビューションをまたいで使う
インストールスクリプトとして
#!/bin/shで配布される場合は、POSIX に準拠してください。 アンチパターンのリファレンスには、移植性のチェックリストがあります。
対応しないこと
- ファイル全体を一度に書き換えないでください。変更ごとに手法を 1 つだけ使い、 その理由が分かるようにしてください。
- 短縮のためだけに新しい依存関係(
yq、jq、parallel)を追加しないでください。 提案はしてもかまいませんが、適用するのはユーザーが同意した場合に限ります。 - 短縮時にコメントや
set -euo pipefailを削除しないでください。 これらは不可欠です。 - 計測せずに、書き換えによって高速になると断言しないでください。
サブプロセスの排除で通常は速くなりますが、両方に対して
timeを実行していない限り、 「5 倍速くなります」ではなく「速くなるはずです」と伝えてください。
レビューで見つけるべきよくある間違い
LLM(または急いでいる人)が bash を短縮しようとすると、 次のような問題がよく発生します。
- 書き換えで
$varが引用符で囲まれていない。 短縮のために 引用符を省略してはいけません。単語分割によるバグは、冗長さよりも深刻です。 - 文字列を返す算術三項演算子。
$((C > 10 ? "high" : "low"))は動作しません。bash の算術演算で扱えるのは整数だけです。[[ $C -gt 10 ]] && S=high || S=lowまたはcaseを使ってください。 (出典記事の例 36 にはこのバグがあり、算術リファレンスでも指摘されています。) - if-then-else のつもりで使う
&& ... || ...。 最初の分岐が失敗しない場合に限り安全です。 最初のコマンドが成功時にゼロ以外を返す可能性が少しでもあれば、||の分岐も実行されます。分岐が複雑な場合はif/elseを使ってください。 -pを付けないmkdir。 短縮によって存在確認が削除されるため、 書き換えを安全にするのは-pフラグです。両方とも削除しないでください。-rまたは-0を付けないxargs。 入力が空の場合やファイル名に空白が含まれる場合、xargsで問題が発生します。空の入力では実行しない-rと、 パスを安全に扱うためのfind -print0と組み合わせた-0を使ってください。 記事では触れられていませんが、レビューで指摘してください。
出典
Karandeep Singh(2023)による https://karandeepsingh.ca/posts/bash-code-shortening-techniques/ の 51 の手法です。 出典記事の番号付き例はすべてリファレンスに残してあり、件数と番号は原文と一致します。