1

I'm quite new on the shell scripting front and was wondering whether it is is possible to call a function which itself than calls another function with none, one or multiple arguments. The first argument would be the name of the function to call, every other argument is an argument for the function to call.

As a background, I want to write a shell script to use some built-in OpenFOAM functions, namely runParallel and runApplication, which, for clarification, I called runSerial in the example above. Those functions do different things, as the name suggests they run a command in either serial or parallel mode.

A simulation in OpenFOAM is made up of multiple function calls and all I want to do is shorten the code so that instead of this

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

I was wondering whether I could replace that with something like this

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

At the moment I'm stuck with the question on how to account for the arguments for the function which my runSerialOrParallel function should call itself. So if I want functionTwo to be run in either serial or parallel, with one argument for functionTwo itself, how do I make that happen inside runSerialOrParallel?

Any help would be greatly appreciated and please forgive me if there is a profane answer to that question which I could easily have found myself but didn't.

cheers!

(I hope the edit cleared some things up, my bad ..)

3
  • Yes, zsh differs from bash, that's why you're using it. Read man zsh or man bash about the shift builtin – waltinator Oct 19 '20 at 17:59
  • 2
    I can't say I understand the question, nor the relation to zsh here as that script has a /bin/sh shebang, but if you want a function to pass its arguments to some other command, whether the shell is sh (Bourne or POSIX), bash or zsh, the syntax is "$@"`. – Stéphane Chazelas Oct 19 '20 at 20:07
  • Thank you @StéphaneChazelas! So your saying inside my runSerialOrParallel function e.g. it should say runSerial "$1" "$@" ? I want the script to run in eiher zsh or bash or anything else, that is why I'm using the shebang and that is why I thought it shouldn't make a difference here @waltinator. I know there are a lot of differences, but I will have a look inside the shift command, thank you! – John_Doe Oct 20 '20 at 6:08
1

In Bourne-like shells "$@" (note that the quotes are important!) expands to all the arguments of the script, or function if expanded inside a function, so here:

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

Would make runSerialOrParallel invoke runSerial or runParallel with the same arguments it received itself. If the first argument is meant to be a function name and the following ones more arguments to pass to that function, then your runSerial function could be something like:

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

(note that whether the first argument is a function, external command or builtin makes no difference here).

Or:

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

(the ${2+s} expands to s if the second argument (initially third) is specified to turn "argument" into plural "arguments" when at least two arguments to $funcName are specified).

$ 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
1
  • Thank you @stephane, that definitely clears things up and solves my problem! – John_Doe Oct 20 '20 at 13:54

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.