やってみる

アウトプットすべく己を導くためのブログ。その試行錯誤すらたれ流す。

Bashの展開

 ~, $1, ${V}など。

成果物

展開一覧

 7種類。展開の順も以下のとおり。

英名 和名 コード例 結果例
1 brace expansion ブレース展開 echo {a..z} a b c ... z
2 tilda expansion チルダ展開 echo ~ /home/USER
3 parameter and variable expansion パラメータ・変数展開 $1,${HOME} /home/USER
4 command substitusion コマンド置換 cd /tmp/work; dirname $(pwd); /tmp
5 arithmetic expansion 算術式展開 echo $((1+1)) 2
6 word splitting 単語の分割
7 pathname expansion パス名展開 cp log{,.bak}.txt log.bak.txtファイル作成

 プロセス置換をサポートできるシステムもある。

英名 和名 コード例 結果例
X process substitution プロセス置換 diff <(echo -e 'A\nB') <(echo -e 'A\nZ')

 なお、シングルクォートされるとそのまま出る。(echo '~'等)

1. ブレース展開

コード 結果
echo {a..z} a b c ... z
echo a{1..3}z a1z a2z a3z
echo {a..z..3} a d g j m p s v y
echo {A,J,Q,K} A J Q K
echo {{a..z},{A..Z},{0..9}} a ... z A ... Z 0 ... 9
コード 結果
touch {A,B} A,Bファイル作成(ls -1 | grep '^[A|B]$')
find /tmp/work/{*.txt,*.sh} findを2回発行
printf "$(printf '\\x%x' {0..127})" | od -t a ASCIIコード一覧
for i in {0..9}; do echo -n "$i "; done; echo; 0〜9までの連番

2. チルダ展開

コード 結果
echo ~ HOME変数値
echo ~+ PWD変数値
echo ~- OLDPWD変数値

3. パラメータ展開

K=V
echo $K
echo ${K}
V
V

3-1. 変数間接展開

VName=Key
Key=Value
echo ${!VName}
Value

3-2. 部分文字列展開

 デフォルト値。

書式 概要 条件 コード例 結果例
${K:-word} wordを返す 変数Kが未定義または空値 unset K; echo ${K:-word}; echo $K; word
${K:=word} wordを代入する 変数Kが未定義または空値 unset K; echo ${K:=word}; echo $K; word
word
${K:?word} エラーを返す 変数Kが未定義または空値 unset K; echo ${K:?未定義または空値です。} bash: K: 未定義または空値です。
${K:+word} wordを返す 変数Kが未定義または空値でない K=V; echo ${K:+word}; echo $K; word
V

 部分文字列。

書式 概要 コード例 結果例
${K:offset}
${K:offset:length}
部分文字列を返す。 K=ABC; echo "${K:1}" BC
K=0123456789; echo -e "${K:6}\n${K:2:4}\n${K::3}\n${K: -4}\n${K: -4:2}\n${K::-1}"
6789
2345
012
6789
67
012345678
A=({0..9}); echo -e "${A[@]:6}\n${A[@]:2:4}\n${A[@]: -4}\n${A[@]: -4:2}"
6 7 8 9
2 3 4 5
6 7 8 9
6 7

 変数名。

書式 概要 コード例 結果例
${!prefix*}
${!prefix@}
前方一致する変数名を返す。複数あればIFS最初の文字で区切る。 K=V; Key=Val; echo "${!K*}" K Key
書式 概要 コード例 結果例
${#K} 長さ A=(A B C); echo ${#A}; 3
K=0123456789; echo ${#K}; A=({a..z});                    # 10   変数
A=({a..z}); echo "${#A[@]}-${#A[0]}";                    # 26-1 配列
declare -A AA=([A]=a [B]=b); echo "${#AA[@]}-${#AA[A]}"; # 2-1  連想配列
書式 概要 コード例 結果例
${!name[@]}
${!name[*]}
配列のキー一覧。nameが配列でないなら0、それ以外は空値。 declare -A AA=([A]=a [B]=b); echo "${!AA[@]}" A B
K=0123456789; echo "${!K},${!K[@]}";                     # ,0         変数
A=({a..z}); echo "${!A[@]},${!A[0]}";                    # 0 1 .. 25, 配列
declare -A AA=([A]=a [B]=b); echo "${!AA[@]},${!AA[A]}"; # A B,       連想配列

 除去。

書式 概要 コード例 結果例
${K#word} 前方最短一致した部分を取り除く。 K=0123456789876543210; echo ${K#*6}; 789876543210
${K##word} 前方最長一致した部分を取り除く。 K=0123456789876543210; echo ${K##*6}; 543210
${K%word} 後方最短一致した部分を取り除く。 K=0123456789876543210; echo ${K%*0}; 012345678987654321
${K%%word} 後方最長一致した部分を取り除く。 K=0123456789876543210; echo ${K%%*0}; (空値)
A=(ABCABC ABCXYZ XYZABC)

# 前方一致削除
echo ${A[@]#AB*}   # CABC CXYZ XYZABC
echo ${A[@]##AB*}  # XYZABC
# パターン削除の記法
echo ${A[@]/#AB*}  # XYZABC

# 後方一致削除
echo ${A[@]%*ABC}  # ABC ABCXYZ XYZ
echo ${A[@]%%*ABC} # ABCXYZ
# パターン削除の記法
echo ${A[@]/%*ABC} # ABCXYZ

 パターン置換。

書式 概要 コード例 結果例
${K/pattern} パターン削除 K=ABCXYZABC; echo "${K/ABC/abc}\n${K//ABC/abc}"; XYZABC XYZ
${K/pattern/string} パターン置換(前方一致1件) K=ABCXYZABC; echo ${K/ABC/abc}; abcXYZABC
${K//pattern/string} パターン置換(部分一致すべて) K=ABCXYZABC; echo ${K//ABC/abc}; abcXYZabc
${K/#pattern/string} パターン置換(前方一致1件) K=ABCXYZABC; echo ${K/#ABC/abc}; abcXYZABC
${K/%pattern/string} パターン置換(後方一致すべて) K=ABCXYZABC; echo ${K/%ABC/abc}; ABCXYZabc
# //#, //%, の`#`,`%`は文字として認識される
K=#ABC; echo "${K//#ABC/abc}";
K=%ABC; echo "${K//%ABC/abc}";
# patternはワイルドカード。メタ文字`?`,`*`が使える
K=ABCXYZABB; echo "${K//AB?/abc}"
K=ABCXYZABC; echo "${K//*X/abcX}"
# 削除(先頭のみ・末尾のみ)
K=ABCXYZABC; echo "${K/#ABC}";
K=ABCXYZABC; echo "${K/%ABC}";
# 複数行に対して一行ずつ一致はできない(改行を含めて全体で「前方一致」「後方一致」「部分一致」のみ)
K="$(echo -e 'ABCXYZABC\nXYZABCXYZ\nABC')"; echo -e "${K/#ABC/abc}";
K="$(echo -e 'ABCXYZABC\nXYZABCXYZ\nABC')"; echo -e "${K/%ABC/abc}";
K="$(echo -e 'ABCXYZABC\nXYZABCXYZ\nABC')"; echo -e "${K//ABC/abc}";
A=(ABCABC ABCXYZ XYZABC)
echo ${A[@]}           # ABCABC ABCXYZ XYZABC
# 削除
echo ${A[@]/BC}        # AABC AXYZ XYZA
echo ${A[@]//BC}       # AA AXYZ XYZA
# 置換
echo ${A[@]/BC/bc}     # AbcABC AbcXYZ XYZAbc
echo ${A[@]//BC/bc}    # AbcAbc AbcXYZ XYZAbc
# 前方一致
echo ${A[@]/#BC/bc}    # ABCABC ABCXYZ XYZABC
echo ${A[@]/#ABC/abc}  # abcABC abcXYZ XYZabc
# 後方一致
echo ${A[@]/%BC/bc}    # ABCAbc ABCXYZ XYZAbc
echo ${A[@]/%ABC/abc}  # ABCabc ABCXYZ XYZabc

 パターン置換(大文字・小文字)。

書式 概要 コード例 結果例
${K^} 最初**のみ大文字 K=abcABC; echo ${K^}; AbcABC
${K,} 最初**のみ小文字 K=ABCabc; echo ${K,}; aBCabc
${K^^} すべて大文字 K=abcABC; echo ${K^^}; ABCABC
${K,,} すべて小文字 K=ABCabc; echo ${K,,}; abcabc

 パターンも書ける。

K=abcABC; echo ${K^?};  # AbcABC
K=abcABC; echo ${K^^?}; # ABCABC
K=ABCabc; echo ${K,*};  # aBCabc
K=ABCabc; echo ${K,,*}; # abcabc

# 文字を指定できる。(文字のみ対象で文字列は指定不可。`${K^ab}`,`${K^^(ab)}`等で文字列`ab`を指定できない)
K=abcABCcbcac; echo ${K^^[ab]};

4. コマンド置換

$(command)
`command`

 command内で実行されたコマンドの標準出力(stdout)を返す。

K="$(ls -1)"
K="`ls -1`"
echo "$K"

 ネストするときは以下。バッククォート式のときは内側のバッククォート\``をバックスラッシュ`でスケープする。

K="$(dirname $(dirname '/tmp/work/a.txt'))"
K="`dirname \`dirname '/tmp/work/a.txt'\``"
echo "$K"

5. 算術式展開

echo $((1+1))
echo $((5-1))
echo $((3*1))
echo $((5/2))
echo $((11%4))
echo $((2**8))
echo $((1+2*3))
echo $(((1+2)*3))

N=0
echo $((N++))
echo $N
echo $((++N))
N=0
echo $((N--))
echo $N
echo $((--N))

echo $((! 2#00 ))
echo $((~ 2#00 ))
echo $(( 2#0001 << 3 ))
echo $(( 2#1000 >> 3 ))
echo $(( 2#01 & 2#10 ))
echo $(( 2#01 | 2#10 ))
echo $(( 2#010 ^ 2#011 ))

echo $(( 0 == 0 ))
echo $(( 0 == 1 ))
echo $(( 0 != 0 ))
echo $(( 0 != 1 ))
echo $(( 0 && 0 ))
echo $(( 0 && 1 ))
echo $(( 1 && 1 ))
echo $(( 0 || 0 ))
echo $(( 0 || 1 ))
echo $(( 1 || 1 ))

echo $(( 0 < 0 ))
echo $(( 0 < 1 ))
echo $(( 0 > 0 ))
echo $(( 0 > -1 ))

echo $(( 0 <= 0 ))
echo $(( 0 <= 1 ))
echo $(( 0 <= -1 ))

echo $(( 0 >= 0 ))
echo $(( 0 >= -1 ))
echo $(( 0 >= 1 ))

echo $(( 0 ? 11 : 22 ))
echo $(( 1 ? 11 : 22 ))
echo $(( 1,2,3 ))

K=0
echo $(( K += 1 ))
echo $(( K *= 9 ))
echo $(( K -= 3 ))
echo $(( K /= 2 ))
echo $(( K %= 2 ))
echo $(( K <<= 3 ))
echo $(( K >>= 3 ))
echo $(( K &= $((2#11)) ))
echo $(( K |= $((2#11)) ))
echo $(( K ^= $((2#101)) ))
# $(( 基数#値 ))
# 2進数
echo $(( 2#00 ))
echo $(( 2#01 ))
echo $(( 2#10 ))
echo $(( 2#11 ))
echo $(( 2#100 ))
echo $(( 2#101 ))
echo $(( 2#110 ))
echo $(( 2#111 ))
# 8進数
echo $(( 8#00 ))
echo $(( 8#77 ))
# 16進数
echo $(( 16#0 ))
echo $(( 16#9 ))
echo $(( 16#a ))
echo $(( 16#A ))
echo $(( 16#f ))
echo $(( 16#F ))
# {{0..9},{a..z},{A..Z}} 62進数
echo $(( 62#0 ))
echo $(( 62#9 ))
echo $(( 62#z ))
echo $(( 62#A ))
echo $(( 62#Z ))
echo $(( 62#10 ))
# {{0..9},{a..z},{A..Z},@,_} 64進数
echo $(( 64#0 ))
echo $(( 64#9 ))
echo $(( 64#z ))
echo $(( 64#A ))
echo $(( 64#Z ))
echo $(( 64#@ ))
echo $(( 64#_ ))
echo $(( 64#10 ))

6. 単語の分解

 単語の分解はIFSの文字をデリミタとする。IFSのデフォルト値は以下。

<Space><Tab><NewLine>

7. パス名展開

  • glob (ワイルドカードでファイル名を指定するパターンのこと)
    • globstarシェルオプションが有効であること(デフォルト)
記号 意味
* 空文字を含む任意文字列。
? 任意の1文字。
[...] 指定条件に一致する1文字
表記 概要
[:class:] 文字クラス
[=a=] a à á â ã ä å A À Á Â Ã Ä Å等にマッチする
[.symbol.]
クラス 概要 補足
alnum [[:alpha:]] + [[:digit:]] \w相当。ロケール依存。
alpha [[:lower:]] + [[:upper:]] ロケール依存。日本語では単語を構成する文字に相当。
ascii おそらくASCIIコードすべて。
blank [ \t](<space>,<tab>) ロケール依存。日本語では全角スペース等に相当。
cntrl [\x00-\x1F\x7F] 制御コード。
digit [0-9] 数字。
graph 印字可&表示可。(スペースは表示不可)
lower [a-z] 日本語では全角小文字アルファベットも含む。
print 印字可。
punct パンクチュエーション(記号)。日本語では句読点や括弧類も含む。
space 空白類。<space>,<tab>,<newline>等。
upper [A-Z] 日本語では全角大文字アルファベットも含む。
word [[:alnum:]] + _ 日本語では単語を構成する文字に相当。
xdigit [[0-9A-Fa-f]] 日本語では全角アルファベットも含む。
./a.sh
cd ../

touch log.txt
ls -1 *.txt
ls -1 *.???
ls -1 [l]*.txt
ls -1 [:alnum:]*.txt

# バックアップ
cp log{,.bak}.txt
cp log{,.$(date "+%Y%m%d%H%M%S")}.txt
# リネーム
mv log{,.append}.txt
mv log{,.$(date "+%Y%m%d%H%M%S")}.txt

 以下、使用頻度が低そうなので無視。

shopt extglob
ls -1 +([:alnum:]).txt
書式 概要
?(pattern-list) 与えられたパターンが 0 回または 1 回現われるとマッチします。
*(pattern-list) 与えられたパターンが 0 回以上現われるとマッチします。
+(pattern-list) 与えられたパターンが 1 回以上現われるとマッチします。
@(pattern-list) 与えられたパターンに 1 回だけマッチします。
!(pattern-list) 与えられたパターンのどれでもないものにマッチします。
  • 他のシェルオプション
    • nullglob
    • failglob
    • nocaseglob
    • dotglob

 以下参考。

X. プロセス置換

<(command)
>(command)
diff <(echo -e 'A\nB') <(echo -e 'A\nZ')
{ echo Out; echo Err >&2; } 2> >(cat) 1>/dev/null
{ echo Out; echo Err >&2; } 1>/dev/null | cat     # >()を使わない方法

対象環境

  • Raspbierry pi 3 Model B+
  • Raspbian stretch 9.0 2018-11-13
  • bash 4.4.12
$ uname -a
Linux raspberrypi 4.14.98-v7+ #1200 SMP Tue Feb 12 20:27:48 GMT 2019 armv7l GNU/Linux