Bash Commands – How to Swap Two Commands in Bash

aliasbash

Say I have command A and command B but I want B to run when I type A and vice versa. I've tried

alias A='B'
alias B='A'

But this doesn't seem to work for some reason.

How do I do this?

EDIT:

Command B has actually been defined as a function in my .bashrc, so

alias A='command B'
alias B='command A'

doesn't work as suggested.

I guess I could update the question to say that A and B could also be functions defined in bash.

Best Answer

So you can get explicit about the way the shell goes about locating commands in a few different ways. You can use...

command command_name

...to instruct the shell only to invoke the command_name if it is a $PATHd executable. This is important in cases like yours because, when you've finished alias A refers to alias B which refers to alias A usually something like 20 times before the alias expansion quits recursing - and which lands you right back where you started. If you wanted to definitely only invoke a $PATHd executable B when calling A and vice versa you can do...

alias A='command B' B='command A'

...which should avoid even calling functions named A or B. Otherwise - because the shell will not expand a quoted alias as an alias but will still call a function even if its command_name is quoted you can quote A and B in the definitions like...

alias A=\\B B=\\A

Ok, so it doesn't recurse twenty times. I could swear I had read that in some man page, but I guess it is at least not true of either bash or ksh (having tested only either of them so far). It, in fact, recurses only twice:

n=0
A(){ echo not B; n=0; }
B(){ echo not A; n=0; }
alias A='echo "$((n+=1))";B' B='echo "$((n+=1))";A'

If I do the above and do...

A

...in bash it prints:

1
2
not B

I guess this is relevant to this from the bash manual:

  • The first word of the replacement text is tested for aliases, but a word that is identical to an alias being expanded is not expanded a second time. This means that one may alias ls to ls -F, for instance, and bash does not try to recursively expand the replacement text.

I had read that before, but I didn't think it would test all expansions leading up to the current expansion when doing so - I figured it would only apply to the latest expansion in the chain. Anyway, that appears to be why.

I did note some interesting behavior otherwise though. After I had already declared both the aliases and the functions I went to rerun the commands, but with a little less intervening white space - like this:

A(){ echo not B; }; B(){ echo not A; }; A; B

...and that did...

1
2
3
4
5
6
not B
7
8
not A

Which means that the shell substituted the alias contents in for the function name - which is not a position one might normally expect an expansion to occur - did the echos and still redefined then executed the functions.

Related Question