Can I write an alias that takes an argument? [duplicate]

I have some remote machines, where I need to compile some source code. What I normally do is write an alias, that says something like:

alias g++='g++ `pkg-config --cflags opencv --libs opencv`'

Then when I go to compile remotely, I would do g++ -o test test.cpp.

For whatever reason, Ubuntu wont let me do that. Instead, Ubuntu works, when I do:

g++ file.cpp -o file `pkg-config --cflags opencv --libs opencv`

But this means I cannot write an alias for g++. Is there a way I can write an alias that will take an argument? what should I do?


Solution 1:

TL;DR: Use command g++ in a shell function instead of g++ in an alias.

As 6.6 Aliases in the Bash reference manual says:

There is no mechanism for using arguments in the replacement text, as in csh. If arguments are needed, a shell function should be used (see Shell Functions).

Although an alias will expand even when it appears in front of additional text, aliases do not themselves support positional parameters (i.e., command-line arguments), so you cannot use an alias to carry out your present task. That is, you cannot use an alias to run a command with user-specified arguments followed by additional arguments.

As you've found, you can use an alias to make g++ file.cpp -o file run:

g++ `pkg-config --cflags opencv --libs opencv` file.cpp -o file

But not to make g++ file.cpp -o file run this command:

g++ file.cpp -o file `pkg-config --cflags opencv --libs opencv`

So, if you want that, you will probably want to use a shell function:

g++ () {
    command g++ `pkg-config --cflags opencv --libs opencv` "$@"
}

You can:

  • Run that on the command-line, and it will be defined as long as the current shell is running, within that shell instance only, or
  • add it to your ~/.bashrc file, and start a new shell or run . ~/.bashrc.

This defines function called g++. Since, unlike aliases, functions can call themselves, I've used the command builtin to prevent undesired recursion. command g++ calls the external g++ command. "$@" expands to all the command-line arguments passed to the function.

In the very rare case that g++ really needed to be an alias, you could "cheat" and define it as an alias to a function (just as you may define an alias to any other command). You could do that either by defining the function first or by defining it each time in the alias (as George suggests). However, there is no need for you to do this; a function will work fine.

Of course, you might not always want g++ to have the output of pkg-config --cflags opencv --libs opencv passed to it. So you might want to put the alias definition in a file and source it only when you want it. If your definition is in g++-fn.sh in your home directory, then to enable the function you can run:

. ~/g++-fn.sh

And to disable the function (no matter how it was defined), you can run:

unset -f g++

I should add that, for anything but tiny or otherwise trivial programs, you should at least consider using make (instead of invoking g++ yourself with the output of pkg-config each time), as steeldriver has suggested.

Solution 2:

Then when I go to compile remotely

That's your main problem. The aliases defined in local config file or local interactive shell, won't work on remote system. Define the alias in your remote machine's ~/.bashrc and it will work then.

A better approach would be to define a function, as Eliah suggested. But you would still have to define it on the remote machine, as with an alias.