関数の基本的な使い方

関数の定義

code
# 関数を定義
func() {
  echo 'func body'
}

# 関数の利用
func
stdout
func body

function ~ 関数の定義

code
# function で関数を定義
function func() {
  echo 'func body'
}

# 関数の利用
func
stdout
func body

function で定義する場合はカッコはあってもなくても定義することができます。

code
# function で関数を定義
# 関数名のあとのカッコはなくても良い
function func {
  echo 'func body'
}

# 関数の利用
func
stdout
func body

関数の引数

code
func() {
  echo "引数の数: ${#*}"
  echo "引数の数: ${#@}"
  echo "1つ目の引数: $1"
  echo "2つ目の引数: $2"
  echo "3つ目の引数: $3"
  echo "すべての引数: ${*}"
  echo "すべての引数(配列): ${@}"
}

func 1 2 3
stdout
引数の数: 3
引数の数: 3
1つ目の引数: 1
2つ目の引数: 2
3つ目の引数: 3
すべての引数: 1 2 3
すべての引数(配列): 1 2 3

関数と変数

code
func() {
  # local で宣言した変数は関数の中でのみ使用できる
  local var2=2

  # var3 は local で宣言していないので関数の外でも使用できる
  var3=3

  # declare で宣言した変数は関数の中でのみ使用できる
  declare -i var4=4

  echo "var1=${var1}"
  echo "var2=${var2}"
  echo "var3=${var3}"
  echo "var4=${var4}"
}

# 関数の外で宣言した変数は関数の中でも利用できる
var1=1

func
echo '------------------------------'
echo "var1=${var1}"
echo "var2=${var2}"
echo "var3=${var3}"
echo "var4=${var4}"
stdout
var1=1
var2=2
var3=3
var4=4
------------------------------
var1=1
var2=
var3=3
var4=

return 関数を途中で終了する

関数を途中で中断し呼び出し元にステータスを戻すには return を使用します。

code
func() {
  echo ' func return before'
  return 0
  echo ' func return after'
}

echo "func before"
func
echo "func after status=$?"
stdout
func before
 func return before
func after status=0

return の引数に指定したステータスが呼び出し元に返されます。

code
func() {
  if [[ $1 == "OK" ]]; then
    echo "> OK"
    return 0
  fi
  echo "> NG: \$1 is $1"
  return 1
}

echo '1. ------------------------------'
func OK
echo "status=$?"
echo '2. ------------------------------'
func NG
echo "status=$?"
stdout
1. ------------------------------
> OK
status=0
2. ------------------------------
> NG: $1 is NG
status=1

ステータスを指定せずに return を使用した場合は最後のコマンドのステータスが使用されます。

code
func() {
  test "${1}" == 'OK'
  return
}

echo '1. ------------------------------'
func OK
echo "status=$?"
echo '2. ------------------------------'
func NG
echo "status=$?"
stdout
1. ------------------------------
status=0
2. ------------------------------
status=1

関数での trap RETURN

RETURN シグナルに trap を設定することで関数の終了時に処理を行うことができます。

code
func() {
  echo 'func start'
  trap 'echo "func trap"' RETURN
  echo 'func end'
}

func
stdout
func start
func end
func trap
code
func() {
  echo 'func start'
  trap 'echo "func trap"' RETURN
  if [[ $1 == '1' ]]; then
    return 1
  fi
  echo 'func end'
  return 0
}

echo '1. ------------------------------'
func 1
echo '2. ------------------------------'
func 2
stdout
1. ------------------------------
func start
func trap
2. ------------------------------
func start
func end
func trap
code
# func2 関数内の trap は func1 関数内の trap で上書きされる
# 結果として func2 関数の終了時にも func1 trap が出力される

func1() {
  echo "${1}func1 start"
  # RETURN シグナルに対する trap が上書きされる
  trap 'echo "${1}func1 trap"' RETURN
  echo "${1}func1 end"
}

func2() {
  echo 'func2 start'
  trap 'echo "func2 trap"' RETURN
  func1 '  '
  echo 'func2 end'
}

func2
stdout
func2 start
  func1 start
  func1 end
  func1 trap
func2 end
func1 trap

上書きした trap の処理の終了時に RETURN シグナルに対する trap をリセットすることで想定した動きになります。

code
func1() {
  echo "${1}func1 start"
  # trap の処理終了時に RETURN シグナルに対する trap をリセット
  trap 'echo "${1}func1 trap"; trap - RETURN' RETURN
  echo "${1}func1 end"
}

func2() {
  echo 'func2 start'
  trap 'echo "func2 trap"' RETURN
  func1 '  '
  echo 'func2 end'
}

func2
stdout
func2 start
  func1 start
  func1 end
  func1 trap
func2 end
func2 trap