Bash Explainer はスクリプトを実行せずに、bash 5.2(bashExplainer.bashVersion を変えれば 5.3)の規則で読みます。このページでは、bash と読み方が違うところと、スクリプトを実行するシェルについて前提にしていることを説明します。
- 解説はルールベースです。辞書にないコマンドは「外部コマンド」として表示され、オプションの詳細は出ません。
- bash と同じには読めない書き方があります。zsh 独自の書き方(
*(.)や${(f)var}。シェルを zsh にすると、その行は「解析できない」と表示されます)、echo ((bash では構文エラーですが、エラーなしで受け付けます)、宣言ビルトインを表すエイリアス(alias d=declareの後、bash はd a=(1 2)をdeclareと同じに読み、d a=$vの$vを分割しません。ここでは前者を構文エラー、後者を分割される引数として解説します)、POSIX モード(set -o posixや sh)でのcommandの後の宣言(bash と dash はcommand declare a=$vやcommand export a=$vの$vを分割せず、dash は\export a=$vも分割しません。ここでは bash の通常モードと同じく分割するものとして解説します)、算術式の中で他の項と並んだ 64 進数の桁@($((64#@))だけなら 62 と読めますが、$((64#@ + 1))では式全体が1つの語になります)、他の文字列の前か後ろに付いた、サブシェルを実行するプロセス置換(<((…)))です(bash はa<((ls))・<((ls))b・x=<((ls))をそれぞれ1つの語と読みますが、ここでは置換が独立した語になります)。[ ]では、構文解析の結果によらず、bash のtestと同じ規則で引数をまとめます(-oは-aより、-aは!より弱く結びつく。オペランドを取る位置の-aと-oは単項演算子)。 - ファイルの最後が、後ろに改行のないバックスラッシュで終わるとき(
echo a\)、解説ではバックスラッシュを語の一部(a\)として示します。bash はこのバックスラッシュを捨てるので、echoはaを表示します。 - 改行が Windows 形式(CRLF)のスクリプトは、LF のものとして解説します。ただし、値は読み取らず、プログラムが受け取る単語には CR を示します(
a␍)。また、bash は各行の最後の語に CR を含めて読むので、そのことを問題(crlf。最初の該当行の最後の語に付きます)として伝えます。毎回失敗するとき(#!の行や、then・fiなどのキーワードの後、コマンドが始まる位置にある CR。空の行や、;・&&・|の後など)はエラー、それ以外(echo hiが CR も出力する)は警告です。このままにしたいときは、独立した行に# bash-explainer disable-file=crlfと書きます(1行目はシェバンなので、その前にdisable=は置けません)。そのようなスクリプトのヒアドキュメントには、bash と同じく終わりの行がありません。 - コマンドがスクリプトとして実行する文字列(
bash -c '…'・eval・trap の動作・ssh host '…')をスクリプトとして解説するのは、中身がそのまま書かれているときだけです。展開を含む文字列(eval "$cmd"・bash -c "cd $dir")の中身は実行するときに決まります。bash fileやsource fileで実行するファイルは読みません。 - 予約語と同じ名前のエイリアス(
alias {=echo・alias [[=echo)は反映しません。エイリアスを展開する設定では、bash は{や[[をその中身に置き換えます({ x; }は構文エラーになり、[[ x ]]はechoを実行します)。しかし解説では、その行をグループや[[ ]]として扱います。 - POSIX モードでは、特殊ビルトインコマンドの前に置いた配列要素への代入(
set -o posix; n[0]=5 :)で、bash は「not a valid identifier」と表示してスクリプトを終了します。解説ではその行が実行されたものとして続きます。 - 展開の値・常に決まる条件・実行されないコードの解説は、スクリプトが既定の環境で始まるものとして出します。環境に bash の変数がなく、bash が既定のオプションで始まる前提です。スクリプト自身が bash の動作を変える場合(
set -k・shopt -s compat42・BASH_COMPAT=42・POSIXLY_CORRECT=1・FUNCNEST=1・BASH_ALIASES・C・POSIX・C.UTF-8以外のロケール)と、先頭行が bash の起動を変える場合(#!/bin/bash -k・#!/usr/bin/env -S BASH_COMPAT=42 bash・bash -O compat31 -c '…')は読み取ります。そのような変更や知らない構文があると、そのスクリプトでは何も決めません。値も、決まる条件も、実行されないコードの印も出しません。ロケールをC・POSIX・C.UTF-8・空にするだけなら、解説は変わりません。 - スクリプトの外のことは見えません。環境の変数(
BASH_COMPAT・POSIXLY_CORRECT・FUNCNEST・SHELLOPTS・BASHOPTS・C 以外のLANGやLC_ALL・bash -xのときのPS4・BASH_ENV・コマンドと同じ名前のエクスポートされた関数)は値や判断を変えられますが、考慮しません。実行時に渡すオプションも見えません。bash -k scriptやsh scriptがそうです(シェルはシェバンか設定から決め、コマンドラインのオプションは分かりません)。そのように実行するスクリプトでは、値や決まる条件の解説を割り引いて読んでください。 - ファイルを開くリダイレクトを、同じディスクリプタの後のリダイレクトが置き換えるとき(
echo hi >a >b)、リンクはたどりません。異なる2つのパスは別のファイルとみなします。ただし、一方に..があるときや、一方が絶対パスで他方が相対パスのとき(>a >b/../a)は「同じファイルを指すなら」と書き添えます。同じファイルを指すシンボリックリンクやハードリンク(ln -s a b; echo hi >a >bはaに書き込みます)は見分けられません。