Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Bash function calling command given as argument

Tags:

alias

bash

eval

How do you write a function in bash that executes the command that it is given as an argument, where

  • The given command may be an alias
  • Arguments must be passed on exactly as given; no evaluating may be done

In other words, how to write an as-transparent-as-possible wrapper function.

The goal of the wrapper function could for example be to set the current directory before and after the given command, and/or set environment variables, or time how long the given command takes,... As a simple example here I take a function that just prints a line and then executes the given command.

A first attempt:

function wrap1 {
   echo Starting: "$@"
   "$@"
}

You could use it like wrap1 echo hello. But the problem is you cannot do alias myalias echo and then call wrap1 myalias hello: it wouldn't resolve the alias.

Another attempt using eval:

function wrap2 {
   echo Starting: "$@"
   eval "$@"
}

Now calling an alias works. But the problem is it evaluates the arguments too. For example wrap2 echo "\\a" prints just a instead of \a because the arguments are evaluated twice.

shopt -s expand_aliases doesn't seem to help here either.

Is there a way to both evaluate aliases like wrap2, but still pass on the arguments directly like wrap1?

like image 259
Wouter Coekaerts Avatar asked Jul 05 '10 10:07

Wouter Coekaerts


People also ask

How do you call a function in bash shell?

To invoke a bash function, simply use the function name. Commands between the curly braces are executed whenever the function is called in the shell script. The function definition must be placed before any calls to the function.

What is $@ in bash?

bash [filename] runs the commands saved in a file. $@ refers to all of a shell script's command-line arguments. $1 , $2 , etc., refer to the first command-line argument, the second command-line argument, etc. Place variables in quotes if the values might have spaces in them.


1 Answers

It seems to be possible with a double eval:

eval "eval x=($(alias y | cut -s -d '=' -f 2))"
# now the array x contains the split expansion of alias y
"${x[@]}" "${other_args[@]}"

So maybe your function could be written as follows:

wrap() {
    eval "eval prefix=($(alias $1 | cut -s -d '=' -f 2))"
    shift
    "${prefix[@]}" "$@"
}

However, eval is evil, and double eval is double evil, and aliases are not expanded in scripts for a reason.

like image 56
Philipp Avatar answered Oct 22 '22 00:10

Philipp