作曲・指導・C言語・Linux

金沢音楽制作

金沢音楽制作では、楽曲・楽譜の制作と、作曲や写譜などレッスンを行っています。

bashの関数の引数に配列を渡す

bashの関数の引数に配列を渡したい時があります。様々な考え方があると思いますが、ここでは名前参照を利用して実現します。なお、筆者の名前参照に対する理解が浅いので、ここに書かれた表現が正確なのかは分かりません。なお、名前参照は、bash 4.3から実装された機能です。

環境:bash 5.1.16

スクリプト例

まずは、実際にコードを見てみましょう。スクリプトの引数にパスを指定すると、テキストと共にそのディレクトリの中身が表示されます。15行目のfn_show_list関数の引数に配列dir_listが渡されているのが分かります。

$ vi dirlist.sh
#!/bin/bash

declare -r dir_name=$1
declare -a dir_list=($(ls ${dir_name}))

fn_show_list() {
  local -n arg=$1

  for array in ${arg[@]}; do
    echo "Exist the ${array} in ${dir_name}"
  done
}

fn_main() {
  fn_show_list dir_list | column -t
}

fn_main

実行すると次のように表示されます。

$ bash dirlist.sh ~/
Exist  Desktop      in  /home/{USER}
Exist  Documents    in  /home/{USER}
Exist  Downloads    in  /home/{USER}
Exist  GoogleDrive  in  /home/{USER}
Exist  Scripts      in  /home/{USER}

詳細解説

では、コードを見ていきましょう。まず、変数と配列の宣言です。宣言は、ビルトインコマンドのdeclareにオプションを付けます。オプションはそれぞれ、-rがread(読み取り専用)、-aがarray(配列)の意味です。

declare -r dir_name=$1
declare -a dir_list=($(ls ${dir_name}))

変数dir_nameに、引数が格納された位置パラメータ(第1引数なら$1、第2引数なら$2)を代入します。そして、配列dir_listに、ls ${dir_name}の結果を代入します。

つぎは、fn_show_list()ではなく、先にfn_main()をみましょう。

fn_main() {
  fn_show_list dir_list | column -t
}

fn_main

fn_main()の中で関数fn_show_listを呼び出しています。また、関数fn_show_listの引数に、配列名dir_listが渡されています。

通常シェルスクリプトで関数の引数に配列を渡すことはできません。じゃあ、ここで渡しているのは何かというと、配列ではなく「配列名」ということになるのでしょうか(自信ありません)。しかし、関数の引数に配列名を渡しただけでは、使うことができません。最後にfn_show_list()をみてみよう。

fn_show_list() {
  local -n arg=$1

  for array in ${arg[@]}; do
    echo "Exist ${array} in ${dir_name}"
  done
}

fn_show_list()で特筆すべきことは、local -n arg=$1-nの部分ですので詳しく見ていきます。

まず、ローカル変数を宣言する、localコマンドにオプション-nを付けてarg宣言し、$1を代入します。この位置パラメーター$1は実行スクリプトの引数ではなく、fn_main()で呼び出されたfn_show_listの引数です。つまり、dir_listという配列名が$1に格納されており、その配列名がargというローカル変数に代入されました。

さて、いよいよ本題です。localに付けられたオプションの-nname reference(名前参照)と呼ばれるものです。名前参照は、変数や配列に入っている値を変数名として、間接的に値を参照できます。つまり、変数argは、配列dir_listを参照します。

あとは変数argfor文で回せば前述の結果が表示されます。ぜひご自身で実験して見てください。

更新情報