bash Tips - コマンド置換と算術式展開、パラメータ展開

# bash Tips - コマンド置換と算術式展開、パラメータ展開

## コマンド置換 - `` `command` ``ではなく``$(command)``を使う

* なぜか？ネストできるから

```shell-session:バッククォートはネストできない
# echo `echo "0123456789abcdefg" | cut -b `echo "11"``
cut: option requires an argument -- 'b'
詳しくは `cut --help' を実行して下さい.
echo 11
```

```shell-session:ダラーと丸括弧ならネストできる
# echo $(echo "0123456789abcdefg" | cut -b $(echo "11"))
a
```

> コマンド置換
> 　　コマンド置換 (command substitution) を用いると、コマンド名をコマンドの出力で置き換えできます。
> 　　コマンド置換には以下の 2 つの形式があります:
> 　　　　\$(command)
> 　　または
> 　　　　\`command\`
> 
> 　　bash による展開は、command の実行およびコマンド置換の部分をコマンドの標準出力と
> 　　置換することにより実行されます。
> 　　この際、末尾の改行文字は削除されます。
> 　　文字列の途中にある改行文字は削除されませんが、単語分割の際に削除されることがあります。
> 　　コマンド置換 \$(cat file) は、同じ意味を持ち、しかも高速な \$(< file) に置き換え可能です。
> 
> 　　バッククォートを使う古い形式の置換を用いたとき、
> 　　バックスラッシュは文字通りの意味を保ちますが、\$、 '、 \、の前にある場合は例外となります。
> 　　バックスラッシュが前置されていないバッククォートがあると、そこでコマンド置換は閉じられます。
> 　　\$(command) という形式を用いたときは、括弧の間にある全ての文字がコマンドとなります。
> 　　特別扱いされる文字はありません。
> 
> 　　コマンド置換は入れ子にできます。
> 　　バッククォート形式の時に入れ子を行うには、
> 　　内側のバッククォートをバックスラッシュでエスケープします。
> 
> 　　置換がダブルクォート内部にある場合には、
> 　　置換の結果に対する単語分割とパス名展開は行われません。
>　　　　　　　　　　　　　　　　　　　　　　　　　　　　　　　　　　　　　　　man bash より引用
 
## 算術式展開 - `expr $m + $n`ではなく`$((m+n))`を使う

* なぜか？bash組み込みであり、インクリメントできるから

```shell-session:exprはインクリメントできない
# i=1; i=$( expr ++$i ); echo "$i"
++1
```

```shell-session:ダラーと丸括弧2重ならインクリメントできる
# i=1; i=$((++i)); echo "$i"
2
```

> 算術式展開
> 　　算術式展開を使うと、算術式を評価して、その結果に置換できます。
> 　　算術式展開のフォーマットを次に示します:
> 　　　　\$((expression))
> 
> 　　expression はダブルクォート内部にある場合と同様に扱われますが、
> 　　括弧の内側のダブルクォートが特別扱いされることはありません。
> 　　式に含まれる全てのトークンに対して、
> 　　パラメータ展開・文字列展開・コマンド置換・クォートの削除が行われます。
> 　　算術式置換は入れ子にできます。
> 
> 　　評価は後述の 算術式評価で示す規則に基づいて行われます。
> 　　expression が不正であれば、 bash は評価の失敗を示すメッセージを出力し、置換を全く行いません。
>　　　　　　　　　　　　　　　　　　　　　　　　　　　　　　　　　　　　　　　man bash より引用

## パラメータ展開

- matsuiによるページを参照
    + [Dokuwiki.fl8.jp » bash » 03 特殊な変数展開](http://dokuwiki.fl8.jp/doku.php/bash/03_special_variable)

> ${parameter:-word}
>     デフォルトの値を使います。 parameter が設定されていないか空文字列であれば、 word を展開したものに置換されます。そうでなければ、 parameter の値に置換されます。
> 
> ${parameter:=word}
>     デフォルトの値を代入します。 parameter が設定されていないか空文字列であれば、 word を展開したものが parameter に代入されます。それから parameter の値への置換が行われます。 位置パラメータや特殊パラメータへの代入をこのように行うことはできません。
> 
> ${parameter:?word}
>     空文字列または設定されていない場合にエラーを表示します。 parameter が空文字列または設定されていない場合、word を展開したもの (word がなければ パラメータが空文字列または設定されていないことを示すメッセージ) が標準エラー出力に出力されます。シェルが対話的でなければ、 シェルは終了します。パラメータに空文字列以外が設定されていれば、 parameter の値への置換が行われます。
> 
> ${parameter:+word}
>     別の値を使用します。 parameter が空文字列または設定されていなければ、空文字列に置換されます。 そうでなければ word を展開したものに置換されます。
> 
> \${parameter:offset:length}
>     部分文字列展開。 parameter を展開したものから最大 length 文字を取り出します。 先頭の文字は offset で指定します。length を省略すると、 offset で指定した文字を先頭にして、 parameter の残り全部が含まれる部分文字列に展開します。 length と offset は算術式です (後述の 算術式評価 を参照)。 offset を評価すると 0 未満の数になる場合、この値は parameter の値の末尾からのオフセットとして使われます。 length を評価すると 0 未満の数になる場合、 parameter が @ ではなく、配列でも連想配列でもなければ、 この値は文字数ではなく parameter の値の末尾からのオフセットとして使われ、 展開結果は 2 つのオフセットの間の部分文字列となります。 parameter が @ ならば、結果は offset から始まる length 個の位置パラメータになります。 parameter が @ または * のインデックスが付いている配列名ならば、 結果は配列の \${parameter[offset]} を先頭とする要素 length 個となります。 負の offset は、指定された配列の最大のインデックス + 1 からの相対値と解釈されます。 連想配列に部分文字列展開した場合の結果は決められていません。 負のオフセットを指定するときには、:- 式と混同されないよう、 1 つ以上の空白でコロンと離す必要があることに注意してください。 位置パラメータを使う場合以外は、 部分文字列のインデックスは 0 から始まります。位置パラメータの場合には、 インデックスは 1 から始まります。 位置パラメータが使われて offset が 0 の場合、 $0 の値が先頭に置かれます。
> 
> \${!prefix*}
> \${!prefix@}
>     前方一致する変数名。 prefix で始まる全ての変数の名前に展開して、 IFS 特殊変数の最初の文字によって区切ります。 ダブルクォートの中で @ が使われた場合、それぞれの変数の名前は 別々の単語に展開されます。
> 
> \${!name[@]}
> \${!name[*]}
>     配列のキーのリスト。 name が配列変数であれば、配列 name の インデックス (キー) のリストに展開されます。 name が配列でない場合は、name が設定されていれば 0 に、 そうでなければ空に展開されます。 ダブルクォートの中で @ が使われた場合、それぞれのキーは 別々の単語に展開されます。
> 
> \${#parameter}
>     パラメータの長さ。 parameter の値に含まれる文字数に置換されます。 parameter が * または @ ならば、位置パラメータの数に置換されます。 parameter が * または @ が添字になっている配列名ならば、配列中の要素数に置換されます。
> 
> \${parameter#word}
> \${parameter##word}
>     パターンに前方一致した部分を取り除く。 word が展開され、パス名展開の場合と同じようなパターンを作ります。 このパターンが parameter の値の先頭部分とマッチする場合、展開して得られる値は parameter を展開した値から最短一致パターン (``#''の場合) または最長一致パターン (``##'' の場合) を取り除いたものになります。 parameter が @ または * である場合、 パターンを削除する操作は全ての位置パラメータに順番に適用され、 展開結果はリストとして得られます。 parameter が @ または * が添字になっている配列変数である場合、 パターンを削除する操作は配列の全ての要素に順番に適用され、 展開結果はリストとして得られます。
> 
> \${parameter%word}
> \${parameter%%word}
>     パターンに後方一致した部分を取り除く。 word が展開され、パス名展開の場合と同じようなパターンを作ります。 このパターンが parameter を展開した値の末尾の部分とマッチする場合、展開結果は parameter を展開した値から最短一致パターン (``%'' の場合) または最長一致パターン (``%%'' の場合) を取り除いたものになります。 parameter が @ または * である場合、 パターンを削除する操作は全ての位置パラメータに順番に適用され、 展開結果はリストとして得られます。 parameter が @ または * が添字になっている配列変数である場合、 パターンを削除する操作は配列の全ての要素に順番に適用され、 展開結果はリストとして得られます。
> 
> \${parameter/pattern/string}
>     パターンの置換。 pattern が展開され、 パス名展開の場合と同じようなパターンを作ります。 parameter の展開が行われ、 その値のうち pattern に最長一致する部分が string に置換されます。 pattern が / で始まる場合には、pattern に マッチした部分は全て string に置換されます。 そうでない場合には、最初にマッチした部分だけが置換されます。 pattern が # で始まる場合には、パターンは parameter を展開した値の先頭にマッチしなければなりません。 pattern が % で始まる場合には、パターンは parameter を展開した値の末尾にマッチしなければなりません。 string が空の場合には pattern にマッチした部分は削除されます。 またこの場合には、pattern の後に続く / は省略可能です。 parameter が @ または * である場合、置換操作は全ての位置パラメータに順番に適用され、 展開結果はリストとして得られます。 parameter が @ または * が添字になっている配列変数である場合、 置換操作は配列の全ての要素に順番に適用され、 展開結果はリストとして得られます。
> 
> \${parameter^pattern}
> \${parameter^^pattern}
> \${parameter,pattern}
> \${parameter,,pattern}
>     大文字小文字の変換。 parameter に含まれるアルファベットの大文字小文字を変換します。 pattern が展開され、 パス名展開の場合と同じようなパターンを作ります。 ^ 演算子は pattern にマッチした小文字を大文字に変換します。 , 演算子は pattern にマッチした大文字を小文字に変換します。 ^^ 演算子と ,, 演算子は、マッチした全ての文字を変換します。 ^ 演算子と , 演算子の場合は、マッチした最初の文字だけ変換します。 pattern を省略した場合、? を指定したものとして扱われ、 全ての文字にマッチします。 parameter が @ または * である場合、大文字小文字の変換は全ての位置パラメータに順番に適用され、 展開結果はリストとして得られます。 parameter が添字に @ または * の付いた配列変数の場合は、配列の要素のそれぞれに大文字小文字の変換が適用され、 結果はリストに展開されます。
> 
>　　　　　　　　　　　　　　　　　　　　　　　　　　　　　　　　　　　　　　　man bash より引用