コマンドを構成する各単語は、そのコマンドが実行されるときに展開されます。展開とは単語に含まれるパラメータやパターンを処理して具体的な文字列値に置き換えることです。展開には以下の七種類があります。
これらの展開は上に挙げた順序で行われます。特に最初の四つ (チルダ展開・パラメータ展開・コマンド置換・数式展開) を四種展開といいます。
チルダ展開は、~
で始まる単語を特定のパス名に置き換える展開です。単語の先頭にある ~
から最初の /
まで (/
がない場合は単語全体) が指定されたパス名に変換されます。ただし、置き換えられる部分が一文字でもクォートされている場合は、チルダ展開は行われません。
展開される内容は、置き換えられる部分の書式によって以下のように決まります。
~
~
は、HOME
変数の値に置き換えられます。
~ユーザ名
~
の後にユーザ名が書かれている場合は、そのユーザのホームディレクトリのパス名に置き換えられます。
~+
~+
は、PWD
変数の値に置き換えられます。
~-
~-
は、OLDPWD
変数の値に置き換えられます。
~+n
~-n
変数代入の値に対してチルダ展開が行われる際、値がコロンで区切ってある場合は、コロンで区切ってある各部分をそれぞれ単語とみなしてチルダ展開します。
チルダ展開に失敗した場合 (指定されたパス名が何らかの原因で得られなかった場合) の動作は POSIX では規定されていませんが、yash では何事もなかったかのように処理を続行します (置き換えられるはずだった部分はそのまま残され、エラーメッセージなどは出ません)。
POSIX 準拠モードでは ~
と ~ユーザ名
の形式の展開のみが有効です。
パラメータ展開は、単語の一部をパラメータの値に置き換える展開です。
よく使われる単純なパラメータ展開の形式は ${パラメータ名}
です。これはパラメータ名で指定されたパラメータの値に展開されます。さらに、以下の場合にはパラメータ名を囲む括弧を省略して $パラメータ名
のように書くこともできます。
${path}-name
という単語は $path-name
と書くこともできますが、${path}name
を $pathname
と書くことはできません。
パラメータ名として特殊パラメータでも位置パラメータでも変数名でもないものを指定した場合は、構文エラーになります。(Yash 以外のシェルでは構文エラーではなく展開エラーになるものもあります)
シェルに nounset オプションが設定されている場合、パラメータ名に存在しない変数を指定すると展開エラーになります。Nounset オプションが設定されていない場合は、存在しない変数は空文字列に展開されます。
より複雑なパラメータ展開の形式では、パラメータの値を加工することができます。パラメータ展開の一般形は以下の通りです。
${ 前置詞 パラメータ名 インデックス 加工指定 }
ここでは便宜上パラメータ名やインデックスの周りに空白を入れましたが、実際には空白を入れてはいけません。パラメータ名以外の部分はいずれも省略可能です。
前置詞としてパラメータ名の直前に記号 #
を置くことができます。この場合、このパラメータ展開はいま展開しようとしている値の文字数を表す整数に展開されます。展開しようとしているのが配列変数の場合、各要素がそれぞれ文字数を表す整数に置き換えられます。
パラメータ名には、特殊パラメータ・位置パラメータ・変数を指定することができます。この場合、パラメータ展開は指定されたパラメータの値に展開されます。指定したパラメータ名が配列変数の場合、配列の各要素が特殊パラメータ @
の場合と同様に単語分割されます (インデックス [*]
が指定された場合を除く)。
パラメータ名としてパラメータ展開・コマンド置換・数式展開を指定することもできます。これは特に展開の入れ子と言います。この場合、パラメータ展開は内側の展開の展開結果に展開されます。なお、内側のパラメータ展開の括弧 { }
は省略できません。また展開の入れ子は POSIX 準拠モードでは使えません。
インデックスは展開する値の一部を抜き出すのに使います。インデックスは以下の書式をしています。
[単語1]
[単語1,単語2]
ここでの単語1および単語2は通常のトークンと同様に解釈されますが、,
と ]
で強制的に区切られます。また空白やタブはトークンの区切りとはみなしません。
インデックスは、以下のように解釈されます。
[単語1]
の書式をしていて、単語1の上記展開結果が *
、@
、#
のいずれかの場合は、インデックスの解釈は終了です。
パラメータ名が配列変数の場合または特殊パラメータ *
または @
の場合、インデックスは配列の要素または位置パラメータの一部を指定しているものとみなされます。例えばインデックスが [2,4]
ならば、配列の 2 番目から 4 番目の要素 (または 2 個目から 4 個目の位置パラメータ) が選択されます。パラメータ名が上記以外の場合は、パラメータの値の一部を指定しているものとみなされます。例えばインデックスが [2,4]
ならば、パラメータの値の 2 文字目から 4 文字目までが選択されます。インデックスで選択された配列の要素またはパラメータの値の一部のみが、パラメータ展開の結果として展開結果に残ります。インデックスによる選択について以下の規則が適用されます。
[-2,-1]
は配列の最後の二つの要素 (またはパラメータの値の最後の 2 文字) を選択します。
[3,5]
が与えられたときは 3 番目以降の全ての要素が選択され、インデックス [5,7]
が与えられた時はどの要素も選択されません。
インデックスが [単語1]
の書式をしていて、単語1の展開結果が *
、@
、#
のいずれかだった場合は、パラメータは以下のように処理されます。
*
*
または @
の場合、全ての位置パラメータを連結し一つの文字列にします。それ以外の場合はインデックス [1,-1]
と同様です。(連結の仕方は特殊パラメータ *
の位置パラメータの連結の仕方と同じです)
@
[1,-1]
と同様です。
#
*
または @
の場合、このパラメータ展開は位置パラメータの個数を表す整数に展開されます。それ以外の場合、このパラメータ展開はいま展開しようとしている値の文字数を表す整数に展開されます。
パラメータ展開にインデックスが指定されていない場合は、インデックスとして [@]
が指定されたものとみなされます。インデックスはPOSIX 準拠モードでは一切使えません。
加工指定はパラメータの値を加工します。加工された後の値がパラメータ展開の結果として展開されます。加工指定には以下の形式があります。
-単語
+単語
=単語
?単語
:-単語
:+単語
:=単語
:?単語
-
、+
、=
、?
と単語の組み合わせの加工指定と同様ですが、単語を使用する条件が異なります。先頭に :
が付かないものでは変数が存在するかどうかで判定されますが、
:
が付くものでは変数が存在し、その値が空文字列でないかどうかで判定されます。
#単語
##単語
#単語
と同様ですが、マッチの仕方が複数通りある場合はできるだけ長くマッチさせる点が異なります。
%単語
#単語
と同様ですが、値の先頭部分ではなく末尾部分にマッチさせる点が異なります。
%%単語
%単語
と同様ですが、マッチの仕方が複数通りある場合はできるだけ長くマッチさせる点が異なります。
/単語1/単語2
/#単語1/単語2
/単語1/単語2
と同様ですが、いま展開しようとしている値の先頭部分にしかマッチしない点が異なります。
/%単語1/単語2
/単語1/単語2
と同様ですが、いま展開しようとしている値の末尾部分にしかマッチしない点が異なります。
//単語1/単語2
/単語1/単語2
と同様ですが、マッチする箇所が複数ある場合は最初の箇所だけではなく全ての箇所を単語2に置き換える点が異なります。
:/単語1/単語2
/単語1/単語2
と同様ですが、いま展開しようとしている値全体にマッチする場合しか対象としない点が異なります。
いずれの形式においても、加工指定に含まれる単語は (それが使用されるときのみ) 四種展開されます。
展開しようとしているパラメータ名が配列変数または特殊パラメータ *
または @
の場合、加工指定は配列の各要素または各位置パラメータに対してそれぞれ作用します。
コマンド置換は、指定されたコマンドを実行してその出力をコマンドラインに展開します。コマンド置換の書式は以下の通りです。
$(コマンド)
`コマンド`
コマンド置換では、コマンドがサブシェルで実行されます。このときコマンドの標準出力がパイプを通じてシェルに送られます。結果として、コマンド置換はコマンドの出力結果に置き換えられます。ただし、コマンドの出力の末尾にある改行は除きます。
$(
と )
で囲んだコマンド置換のコマンドは、コマンド置換の入れ子やリダイレクトなどを考慮して予め解析されます。従って、$(
と )
の間には基本的に通常通りコマンドを書くことができます。ただし、数式展開との混同を避けるため、中のコマンドが (
で始まる場合はコマンドの最初に空白を挿し挟んでください。
`
で囲むコマンド置換では、コマンド置換の入れ子などは考慮せずに、コマンドの中に最初に (バックスラッシュでクォートしていない) `
が現れたところでコマンド置換の終わりとみなされます。`
で囲んだコマンド置換の中に `
で囲んだコマンド置換を書く場合は、内側の `
をバックスラッシュでクォートする必要があります。その他、コマンドの一部として `
を入れたいときは、(それがコマンド内部で一重または二重引用符でクォートされていても) バックスラッシュでクォートする必要があります。
$(
と )
で囲んだコマンド置換の中のコマンドは、そのコマンド置換を含むコマンドを解析する時に一緒に解析されます (POSIX 準拠モードを除く)。`
で囲んだコマンド置換の中のコマンドは、POSIX 準拠モードであるかどうかに関わらず、そのコマンド置換が実行される時に毎回解析されます。
数式展開は、文字列を数式として解釈して、その計算結果を表す数値に展開します。数式展開の書式は以下の通りです。
$((式))
数式展開では、まず式に対してパラメータ展開・コマンド置換・(入れ子の) 数式展開が行われます。その結果得られた文字列を以下のように数式として解釈し、その計算結果を表す数値に展開されます。
Yash では、数式の中で整数 (C 言語の long 型) と浮動小数点数 (C 言語の double 型) を扱うことができます。ただし POSIX 準拠モードでは浮動小数点数は使えません。整数同士の演算の結果は整数に、浮動小数点数を含む演算の結果は浮動小数点数になります。
数式では C 言語と (ほぼ) 同様に以下の演算子が使えます。
( )
++
、--
(後置演算子)
++
、--
、+
、-
、~
、!
(前値演算子)
*
、/
、%
+
、-
<<
、>>
<
、<=
、>
、>=
==
、!=
&
^
|
&&
||
? :
(三項演算子)
=
、*=
、/=
、%=
、+=
、-=
、<<=
、>>=
、&=
、^=
、|=
原子式としては整数リテラル・浮動小数点数リテラル・変数が使用できます。数リテラルの書式は C 言語に準じます。0
で始まる整数リテラルは八進数、0x
で始まる整数リテラルは十六進数とみなされます。浮動小数点数リテラルでは指数表記も使えます (例えば 1.23×106 は 1.23e+6
)。変数は、その値が数値でない場合はエラーになります。
ブレース展開は、ブレース ({ }
) で囲んだ部分をいくつかの単語に分割します。ブレース展開は braceexpand オプションが有効な時のみ行われます。ブレース展開には二種類の形式があります。
一つ目の形式は、ブレースで囲んだ部分を一つ以上のカンマ (,
) で区切ったものです。区切られたそれぞれの部分がブレース展開の前後の部分と結合されて、それぞれ単語として展開されます。例えば a{1,2,3}b
は a1b
、a2b
、a3b
という三つの単語に展開されます。
二つ目の形式は {始点..終点}
または {始点..終点..差分}
です。始点・終点・差分は全て整数である必要があります。この形式のブレース展開では、始点から終点までの各整数がブレース展開の前後の部分と結合されて、それぞれ単語として展開されます。差分は整数の間隔を指定します。例えば a{1..3}b
は a1b
、a2b
、a3b
という三つの単語に展開され、a{1..7..2}b
は a1b
、a3b
、a5b
、a7b
という四つの単語に展開されます。始点が終点より大きい場合は整数は降順に展開されます。
複数のブレース展開を組み合わせたり、入れ子にしたりすることもできます。ブレースをブレース展開としてでなく通常の文字として扱うには、ブレースをクォートしてください。またカンマを区切りとしてでなく通常の文字として扱うには、カンマをクォートしてください。
ブレース展開では展開エラーは発生しません。ブレース展開が正しくできない場合は、単にそれはブレース展開ではなかったものとして、そのまま残されます。
単語分割は、展開の結果をいくつかの単語に分割します。
単語分割で分割の対象となるのは、パラメータ展開・コマンド置換・数式展開で展開された結果の部分だけです。また、二重引用符によるクォートの中で展開された部分は、(特殊パラメータ @
の展開を除いて) 分割の対象となりません。
単語分割は IFS
変数の値に従って行われます。IFS
変数が存在しない場合は、空白文字・タブ・改行の三文字が IFS
変数の値として使われます。
IFS
変数の値に含まれている文字を IFS 文字といいます。IFS 文字のうち空白文字またはタブまたは改行であるものを IFS 空白類といいます。IFS 空白類以外の IFS 文字を IFS 非空白類といいます。
分割は以下の規則に従って行われます。
注: IFS
変数の値が空文字列の場合は、単語は一切分割されません。
パス名展開は、単語をパターンとみなしてファイルを検索し、パターンにマッチする実在のファイルへのパス名に展開します。パス名展開は noglob オプションが有効な時は行われません。
パス名展開においてパターンがマッチするには、検索の対象となるディレクトリの読み込み権限が必要です。検索しようとしたディレクトリがシェルにとって読み込み可能でなければ、シェルはそのディレクトリは空であるとみなします。
以下のオプションがパス名展開の結果に影響します。(これらのオプションは最初はすべて無効になっています。)
*
や ?
などのワイルドカードやブラケット記法で始まるパターンはピリオドで始まるファイル名にマッチしません。しかしこのオプションが有効な時はこのような制約は解除されます。
/
が付きます。
パス名展開ではエラーは発生しません。マッチするファイルがない場合またはパターンが不正な場合は、展開は行われずパターンはそのまま残ります (nullglob オプションが有効な時を除く)。
ファイルの検索とパターンマッチングは /
で区切られたパス名の構成要素ごとに行われます。ワイルドカードやブラケット記法を全く含まない構成要素はパターンとはみなされず、検索とマッチングは行われません。従って、nocaseglob オプションが有効な時、/*/foo
と /*/fo[o]
の展開結果が異なる可能性があります (前者では foo
の部分がパターンとはみなされないので、例えば /bar/FOO というファイルがあってもマッチしません。)。
Extendedglob オプションが有効な時は、以下の特殊なパターンが使えるようになります。
**
dir/**/file
というパターンは、dir/file や dir/foo/file や dir/a/b/c/file など、dir ディレクトリの中にある全ての file ファイルへのパスに展開されます。
foo/bar/**
のようにパターン全体の最後にある場合には効果がありません。
.**
**
パターンと同様ですが、名前がピリオドで始まるディレクトリも含めて検索する点が異なります。
***
**
パターンと同様ですが、検索の中でディレクトリへのシンボリックリンクが見つかった場合、そのディレクトリの中も検索の対象に含める点が異なります。
.***
***
パターンと同様ですが、名前がピリオドで始まるディレクトリも含めて検索する点が異なります。