4

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.

  • 2
    alias A='command B' B='command A'. Or, if you're certain that the only reference you want to avoid is the alias you've just defined, then alias A=\\B B=\\A. – mikeserv Mar 1 '15 at 12:05
  • Option 2 worked, this could have been posted as an answer, thanks! Option 1 didn't work, I think it is because B is actually a function defined in my .bashrc. I don't understand what you mean by "the only reference you want to avoid is the alias" - could you explain that further please? – texasflood Mar 1 '15 at 12:18
  • I guess you did update the question to say that... haha. – mikeserv Mar 1 '15 at 17:09
  • Oh yeah so I did :P – texasflood Mar 1 '15 at 17:55
5

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.

  • Nice analysis, turns out the expansion rules are quite complicated. I guess you have to careful with circular aliases! Maybe one day I'll look at the code for alias expansion and post a more general explanation. – texasflood Mar 1 '15 at 22:35
  • Ok the solution has worked fine so far, I have been using alias man=\\vman vman=\\man where man is just the ordinary man pages and vman is a custom defined function in my .bashrc. When I run source ~/.bashrc, I get the following error: bash: '\man': not a valid identifier. This error doesn't appear when opening a new terminal. Why does this happen? – texasflood Mar 12 '15 at 17:55
  • @texasflood - I would guess you are quoting the assignment in that case? Like alias 'vman=\\man' maybe? If not I can't say for sure, but you can get a better idea by doing set -vx at the top of your environment file. – mikeserv Mar 12 '15 at 18:01
  • Ok, the output from that produces bash: '\man': not a valid identifier right after the definition of vman(), and then I have the alias, alias man=\\vman vman=\\man, and then it seems to add the alias as per the line below: ++ alias 'man=\vman' 'vman=\man' – texasflood Mar 12 '15 at 18:42
  • 1
    @texasflood - ahh! I get it. You're sourcing your environment file - so those aliases are already defined when you do. It's exactly what I mentioned here in the answer - the alias is substituting even in the the function definition command - so you're doing vman()... but really doing ${contents of alias vman -> man} \man()... – mikeserv Mar 12 '15 at 20:15

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.