Monday, July 11, 2022

[SOLVED] Bash : how to use a function (which is a string param) in an other function

Issue

I have these functions in my .bashrc:

# This function just untar a file:
untar()
{
    tar xvf $1
}

# This function execute a command with nohup (you can leave the terminal) and nice for a low priority on the cpu:
nn()
{
    nohup nice -n 15 "$@" &
}

Before testing the nn function, I create a tar:

echo test > test.txt
tar cvf test.txt.tar test.txt

Now what I want to do is:

nn untar test.txt.tar

But only this works:

nn tar xvf test.txt.tar

Here the error in nohup.out:

nice: ‘untar’: No such file or directory

Solution

Functions are not first-class citizens. The shell knows what they are, but other commands like find, xargs, and nice do not. To call a function from another program you need to (a) export it to sub-shells, and (b) explicitly invoke a sub-shell.

export -f untar
nn bash -c 'untar test.txt.tar'

You could automate this if you want to make it easier for the caller:

nn() {
    if [[ $(type -t "$1") == function ]]; then
        export -f "$1"
        set -- bash -c '"$@"' bash "$@"
    fi

    nohup nice -n 15 "$@" &
}

This line deserves an explanation:

set -- bash -c '"$@"' bash "$@"
  1. set -- changes the current function's arguments; it replaces "$@" with a new set of values.
  2. bash -c '"$@"' is the explicit subshell invocation.
  3. bash "$@" are the arguments to the subshell. bash is $0 (not used). The outer existing arguments "$@" are passed to the new bash instance as $1, $2, etc. This is how we get the subshell to execute the function call.

Let's see what happens if you call nn untar test.txt.tar. The type -t check sees that untar is a function. The function is exported. Then set changes nn's arguments from untar test.txt.tar to bash -c '"$@"' bash untar test.txt.tar.



Answered By - John Kugelman
Answer Checked By - Terry (WPSolving Volunteer)