記法、引数、戻り値、変数(local
, local -r
)。
成果物
構文
MyFunc() { echo F; } MyFunc
意味 | コード例 |
---|---|
定義 | MyFunc() { echo F; } |
実行 | MyFunc |
関数はfunction
を付与して定義するが省略できる。
function MyFunc() { echo F; }
引数
$n
(n
は数値)で位置引数を取得する。
Sum() { echo $(($1 + $2)); } echo $(Sum 10 20)
$0
はスクリプトファイルパス。コマンドラインシェルのときはシェル実行ファイル名。
ParentDir="$(dirname $0)"
$@
はすべての引数。""
で囲むとスペースも含まれたひとつの文字列になる。""
で囲まないとスペース区切りの単語になる。
Msg() { echo "$@"; } Msg "やあ" "hello world."
Msg() { for msg in $@; do echo $msg; done; } Msg "やあ" "hello world."
getopts
コマンドで引数解析できるが、複雑な解析はできない。
終了コード取得
MyFunc() { return 255; } MyFunc RET=$? echo $RET
関数は終了コードを設定できる。return
(exit
)の第一引数に0
〜255
の数値を渡すことで。0
が正常、1
〜255
が異常。その他の値は不可。
もしreturn
に文字列を指定すると実行時エラーになる。
MyFunc() { return 'A'; } MyFunc
bash: return: A: 数字の引数が必要です
stdout取得
MyFunc() { echo 'RESULT'; } RET="$(MyFunc)" echo $RET
関数から文字列を受け取りたいなら、コマンド置換によりstdoutを取得する。
local
変数
MyFunc() { local RET="RESULT"; echo "$RET"; } RET="$(MyFunc)" echo $RET
関数内でのみ使用可。local
を付与すれば関数内のみ参照できる変数を使える。グローバル変数を作らないので名前汚染を防げる。
set -u
で未割当時にエラーとすると確認できる。
set -u MyFunc() { local RET="RESULT"; echo "$RET"; } echo $RET
bash: RET: 未割り当ての変数です
同名のグローバル変数とローカル変数が宣言されたときの話。関数内での参照は同名グローバル変数よりも同名ローカル変数が優先して参照される。
RET=GLOBAL MyFunc() { local RET="RESULT"; echo "$RET"; } RET="$(MyFunc)" echo $RET
RET=GLOBAL MyFunc() { echo "$RET"; } RET="$(MyFunc)" echo $RET
同名ローカル変数があったとき同名グローバル変数を参照する方法はない。と思う。
local -r
local
かつreadonly
にする。
MyFunc() { local -r RET="RESULT"; RET="A"; echo "$RET"; } RET="$(MyFunc)" echo $RET
再代入エラーが出る。
bash: RET: 読み取り専用の変数です
readonly
グローバル変数のみ対象。
readonly RET="RESULT" RET="A"
再代入しようとすると以下のエラーになる。
bash: RET: 読み取り専用の変数です
local
との併用はできない。ふつうに再代入されてしまう。
MyFunc() { local readonly RET="RESULT"; local readonly RET="A"; echo "$RET"; } MyFunc() { local readonly RET="RESULT"; local RET="A"; echo "$RET"; } MyFunc() { local readonly RET="RESULT"; RET="A"; echo "$RET"; } RET="$(MyFunc)" echo $RET
local -r
を使うべし。
1行データずつ関数を呼ぶ
while read
で1行ずつ処理する。
Msg() { echo "MSG: $1"; } seq 1 3 | while read line; do { Msg ${line}; }; done;
ワンライナーにすると以下。
Msg() { echo "MSG: $1"; }; seq 1 3 | while read line; do { Msg ${line}; }; done;
もし1行データを累計したいなら以下。
Add() { echo "$(($1+1))"; } seq 1 3 | ( SUM=0; while read line; do { SUM=$((SUM+$(Add $line))); }; done; echo $SUM )
ワンライナーにすると以下。
Add() { echo "$(($1+1))"; }; seq 1 3 | ( SUM=0; while read line; do { SUM=$((SUM+$(Add $line))); }; done; echo $SUM );
xargsで関数を呼ぶ
while
の代わりにxargs
を使うと以下。
Msg() { echo "MSG: $1"; } export -f Msg seq 1 3 | xargs -I@ bash -c 'Msg @'
ポイントはexport -f Msg
。xargs bash -c '...'
だと別プロセスとなり関数が未定義になる。そこでシェル変数から環境変数へ出力してプロセス間共有させる。export -f 関数名
で。
ワンライナーにすると以下。
Msg() { echo "MSG: $1"; }; export -f Msg; seq 1 3 | xargs -I@ bash -c 'Msg @';
集計はわからん。
対象環境
- 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