🎉
[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