🎉
[Bash]特殊変数とパラメータ展開
はじめに
いつも忘れるし、ググるのも大変だしメモ。
シェル芸の初歩として、特殊変数とパラメータ展開についてまとめました。
- 試したバージョン
$ bash --version GNU bash, version 5.0.17(1)-release (x86_64-pc-linux-gnu) Copyright (C) 2019 Free Software Foundation, Inc. License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html> This is free software; you are free to change and redistribute it. There is NO WARRANTY, to the extent permitted by law.
特殊変数
一覧
変数 | 説明 | 備考 |
---|---|---|
$0 | シェルスクリプト名 | |
$1~9 | シェルスクリプトに渡される引数 | 10番目以降は${10}のように書く。 |
$* | シェルスクリプトに渡される引数全て | |
$@ | シェルスクリプトに渡される引数全て | |
$# | シェルスクリプトに渡される引数の数 | |
$? | 最後に実行したコマンドの終了ステータス | |
$$ | シェルスクリプトのPID | |
$! | 最後に実行したバックグラウンドプロセスのPID |
$*
と$@
の違い
$*
は1つの要素であるとみなされるのに対し、$@
は要素が分かれています。
実際に以下を実行してみるとわかりやすいです。
-
ソースコード
sample_test_args.sh#!/bin/bash echo -e "\n\$* test" for arg in "$*";do echo $arg; done; echo -e "\n\$@ test" for arg in "$@";do echo $arg; done;
-
実行結果
$ ./sample_test_args.sh a b c $* test a b c $@ test a b c
プロセスについて
$$
はシェルスクリプトのPIDを表示しますが、Bash4から$BASHPID
という変数が登場しました。
基本的には一緒のPIDを表示しますが、サブシェルの時に挙動が変わります。
-
$$
: シェルスクリプトのPID -
$BASHPID
: シェルスクリプトのPID(サブシェルの時はサブシェル自身のPID) -
ソースコード
sample_test_pid.sh#!/bin/bash ( echo "\$\$ is $$" echo "\$BASHPID is ${BASHPID}" sleep 3 ) & ps -ef --forest | grep -i 'bash' | grep -v grep
-
実行結果
$ ./sample_test_pid.sh $$ is 11440 $BASHPID is 11443 ***** 7484 10856 0 09:50 pts/6 00:00:00 | \_ /bin/bash ***** 11440 7484 0 10:13 pts/6 00:00:00 | | \_ /bin/bash ***** 11443 11440 0 10:13 pts/6 00:00:00 | | \_ /bin/bash
パラメータ展開
bashにはパラメータ展開という機能があります。
個人的にはデフォルト値を入れたりとか、文字列の一部を取り出したいときによく使用します。
一覧
一部を抜粋して一覧化しています。
式 | 説明 | 備考 |
---|---|---|
${parameter:-word} | parameterが未設定であればwordを使用。parameterへの代入はなし | |
${parameter:=word} | parameterが未設定であればwordを使用。parameterへの代入あり | |
${parameter:+word} | parameterが設定されていればwordを使用。未設定であれば空文字。parameterへの代入あり | |
${parameter+word} | parameterが未設定であればwordを使用。未設定であれば空文字。parameterへの代入なし | |
${parameter:offset} | parameterからoffset(0始まり)以降の文字列を抜き出す | |
${parameter:offset:length} | parameterからoffset(0始まり)以降の文字列をlength分抜き出す | |
${#parameter} | parameterの文字数をカウント | |
${parameter/pattern/string} | parameterでpatternにマッチした部分をstringに置換 (1回のみ) | |
${parameter//pattern/string} | parameterでpatternにマッチした部分をstringに置換 (全て) | 正規表現のgオプションに相当 |
デフォルト値
${parameter:-word}
と${parameter:=word}
はparameterが未設定であればデフォルト値wordが入ります。
変数parameterにwordを代入するか否かで両者に違いがあります。
- ソースコードsample_test_default.sh
#!/bin/bash arg1="$1" arg2="$2" echo -e "\n\${parameter:-word} test" echo ${arg1:-"word"} echo ${arg2:-"word"} echo -e "\nIs \${arg2} set default value?" echo ${arg2} echo -e "\n\${parameter:=word} test" echo ${arg1:="word"} echo ${arg2:="word"} echo -e "\nIs \${arg2} set default value?" echo ${arg2}
- 実行結果
$ ./sample_test_default.sh foo ${parameter:-word} test foo word Is ${arg2} set default value? ${parameter:=word} test foo word Is ${arg2} set default value? word
文字列抜き出し
offsetとlengthの指定でparameterの任意の位置の文字を抜き出すことができます。
末尾から抜き出すこともできるので便利ですね。
これでcutを使わなくてもいけます。
- ソースコードsample_test_substring.sh
#!/bin/bash arg1="$1" arg2="$2" echo -e "\n\${parameter:offset(3)} test" echo ${arg1:3} # 文字列の長さよりも大きい値をoffsetで指定してもエラーにならない echo ${arg2:3} echo -e "\n\${parameter:offset(-3)} test" # offsetにマイナスの値を入れると、末尾から数えてoffset以降の文字を抜き出す # ※コロンの間に半角スペースを入れることに注意 echo ${arg1: -3} echo -e "\n\${parameter:offset(3):length(2)} test" echo ${arg1:3:2} # 文字列の長さよりも大きい値をoffset, lengthで指定してもエラーにならない echo ${arg2:3:2} echo -e "\n\${parameter:offset(3):length(-2)} test" # lengthにもマイナスの値を入れられる。length分を引いた文字を抜き出す echo ${arg1:3:-2}
- 実行結果
$ ./sample_test_substring.sh foobarbaz ${parameter:offset(3)} test barbaz ${parameter:offset(-3)} test baz ${parameter:offset(3):length(2)} test ba ${parameter:offset(3):length(-2)} test barb
おわりに
スマートかつ簡潔に書けるのは良いと思う反面、わからないとドツボにはまりそうですね。。。
まだまだ未熟ですが、これから精進します。押忍!
参考にした記事
以下参考にさせていただきました。ありがとうございます。
Discussion