chamar função pelo nome com argumentos

Oct 20 2020

Sou bastante novo no front de script de shell e queria saber se é possível chamar uma função que por si só chama outra função sem nenhum, um ou vários argumentos. O primeiro argumento seria o nome da função a ser chamada, todos os outros argumentos são um argumento da função a ser chamada.

Como pano de fundo, desejo escrever um script de shell para usar algumas funções integradas do OpenFOAM, a saber runParallele runApplication, que, para esclarecimento, chamei runSerialno exemplo acima. Essas funções fazem coisas diferentes, como o nome sugere, elas executam um comando no modo serial ou paralelo.

Uma simulação em OpenFOAM é composta de várias chamadas de função e tudo que eu quero fazer é encurtar o código para que, em vez disso

#!/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

Eu estava me perguntando se eu poderia substituir isso por algo assim

#!/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"

No momento, estou preso à questão de como explicar os argumentos da função que minha runSerialOrParallelfunção deve chamar a si mesma. Portanto, se eu quiser functionTwoser executado em série ou paralelo, com um argumento para functionTwosi mesmo, como faço isso acontecer internamente runSerialOrParallel?

Qualquer ajuda seria muito apreciada e por favor me perdoe se houver uma resposta profana para essa pergunta que eu poderia facilmente ter encontrado, mas não encontrei.

Felicidades!

(Espero que a edição tenha esclarecido algumas coisas, meu mal ..)

Respostas

1 StéphaneChazelas Oct 20 2020 at 14:53

Em shells tipo Bourne "$@"(observe que as aspas são importantes!) Se expande para todos os argumentos do script, ou função se expandida dentro de uma função, então aqui:

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

Faria runSerialOrParallelinvocar runSerialou runParallelcom os mesmos argumentos que se recebeu. Se o primeiro argumento for um nome de função e os seguintes mais argumentos a serem passados ​​para essa função, sua runSerialfunção poderia ser algo como:

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

(note que se o primeiro argumento é uma função, comando externo ou embutido não faz diferença aqui).

Ou:

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" "$@"
}

(o ${2+s}expande para sse o segundo argumento (inicialmente terceiro) for especificado para transformar "argumento" em "argumentos" no plural quando pelo menos dois argumentos para $funcNameforem especificados).

$ 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