名前とパラメータで関数を呼び出す

名前とパラメータで関数を呼び出す

私はシェルスクリプトに最初に触れましたが、パラメータなしで1つ以上のパラメータを使用して別の関数を呼び出すのではなく、関数自体を呼び出すことができるかどうかを知りたいです。最初のパラメータは呼び出す関数の名前、残りのパラメータはそれぞれ呼び出す関数のパラメータです。

背景知識として、私は説明のために上記の例で呼び出されたいくつかの組み込みOpenFOAM関数、つまりおよびをrunParallel使用するシェルスクリプトを作成したいと思います。これらの関数は、名前が示すようにさまざまな操作を実行し、シリアルモードまたはパラレルモードでコマンドを実行します。runApplicationrunSerial

OpenFOAMのシミュレーションはいくつかの関数呼び出しで構成されています。

#!/bin/sh

# $n_core is a user input how many cores to use
printf 'On how many cores do you want to run the simulation?'
read -r n_core

if [ $n_core -eq "1" ]; then
  runSerial "functionOne"  # no arguments here
  runSerial "functionTwo" "arg1"
  runSerial "functionThree" "arg1" "arg2"
  ...
else
  runParallel "functionOne"  # no arguments here
  runParallel "functionTwo" "arg1"
  runParallel "functionThree" "arg1" "arg2"
  ...
fi

こんなものに置き換えることができるか悩んでいたのに

#!/bin/sh

runSerialOrParallel()
{
    if [ $n_core -eq "1" ]; then
        runSerial "$1" "$2" ...
    else
        runParallel "$1" "$2" ...
    fi
}

# $n_core is a user input how many cores to use
printf 'On how many cores do you want to run the simulation?'
read -r n_core

runSerialOrParallel "functionOne"  # no arguments here
runSerialOrParallel "functionTwo" "arg1"
runSerialOrParallel "functionThree" "arg1" "arg2"

runSerialOrParallel現在私は、関数が自分で呼び出す必要がある関数パラメータを解釈する方法について心配しています。それでは、functionTwoシリアルまたはパラレルで実行し、パラメータがある場合はfunctionTwo内部的にこれを達成しますかrunSerialOrParallel

どんな助けでも大変感謝します。この質問について私は簡単に見つけることができましたが、見つからなかった神聖な冒涜的な答えがある場合は許してください。

乾杯!

(編集者がいくつかのことを明確にしてくれることを願っています。残念です。)

ベストアンサー1

Bourneのようなシェル"$@"(引用符が重要です!)では、拡張はスクリプト内のすべての引数に適用されるか、関数内で拡張されると関数に適用されます。したがって、次のようになります。

runSerialOrParallel()
{
    if [ "$n_core" -eq 1 ]; then
        runSerial "$@"
    else
        runParallel "$@"
    fi
}

自分が受け取ったのと同じ引数を使用してrunSerialOrParallel呼び出されますrunSerialrunParallel最初の引数が関数名で、次の引数が関数に渡される場合、関数は次のようになりますrunSerial

runSerial() {
  printf 'Running "%s" with %u argument%s:\n' "$1" "$(($# - 1))" "${3+s}"
  "$@"
}

(最初の引数が関数なのか、外部のコマンドなのか、組み込み関数なのかはここでは違いはありません。)

または:

runSerial() {
  funcName=${1?No function specified}
  shift # removes the func name from the arguments

  printf 'Running "%s" with %u argument%s:\n' "$funcName" "$#" "${2+s}"
  "$funcName" "$@"
}

(少なくとも2つの引数が指定されている場合、2番目(最初は3番目)引数が指定されている場合は、${2+s}「引数」を複数の「引数」に変換するように拡張されます。)s$funcName

$ runSerial echo foo bar
Running "echo" with 2 arguments:
foo bar
$ runSerial echo foo
Running "echo" with 1 argument:
foo
$ n_core=1
$ runSerialOrParallel echo foo
Running "echo" with 1 argument:
foo

おすすめ記事