ヒトリ歩き

愚痴とかいろいろ書きます

シェルスクリプトで参照渡し?

最近、業務でシェルスクリプトを書く機会が多かったのですが、なるべく汎用的に使える関数にしたいし、グローバル変数も使用したくないので、どうにか参照渡しのようなことが出来ないか調べてみたところ、evalコマンドを使うと実現可能だということが分かったので紹介します。

evalコマンドとは

指定した文字列を評価後に連結して、現在のシェルに実行させることができるコマンドです。
www.atmarkit.co.jp

参照渡しもどきをやるにはどうすればいいのか?

evalコマンドで、設定したい変数名を格納した変数を左辺に設定し、設定した値を右辺に設定することで参照渡しもどきが可能です。

eval "${設定したい変数名を格納した変数}=設定したい値"

下記がサンプルコードになります。
isNotEmptyAndGetValue関数の第2パラメータに変数名(str2)を渡しています。
isNotEmptyAndGetValue関数でevalコマンドを利用してstr2変数に値を設定します。

#!/bin/bash

function isNotEmptyAndGetValue() {

    local str="$1"
    local valueKey="$2"

    if [[ -z ${str} ]] ; then
        return 1
    fi

    # 参照渡しもどき?
    eval "${valueKey}=$(echo ${str} | awk -F= '{print $2}')"
    return 0
}

function main() {

    local str1=""
    isNotEmptyAndGetValue "" str1
    echo "\$?=$? \$str1=${str1}"

    local str2=""
    isNotEmptyAndGetValue "key=aaa" str2
    echo "\$?=$? \$str2=${str2}"
}

main

valueKeyにstr2変数名が設定されており、evalコマンドによってvalueKey変数がstr2へ展開されます。
これが。

eval "${valueKey}=$(echo ${str} | awk -F= '{print $2}')"

こうなる。

eval str2=aaa

本当に参照渡しもどきをやらないといけないか考えて使おう

実際の処理では、関数の中で必要な文字列のチェックを行いながら、文字列を加工していたので、参照渡しもどきの手法を使いました。

ただ、関数に変数名を渡すのはどうなのか?

リファクタリングで変数名を変更した場合、関数に渡す変数名も変更する必要が出てきます。
もし、関数に渡す変数名の変更が漏れてしまったら、デグレードが発生することになります。
本当に参照渡しもどきが必要?
他に方法はないか?
検討して使用することをオススメします。