Can ',,' be aliased to '..'?

41

8

Sometimes when I want to change to the parent directory, I mistakenly type cd ,, instead of cd ... Is there a way I can make bash consider these statements to be the same? I never use commas in my commands. Ideally, I would like to alias ,, to ... When I tried this, it didn't work. Why didn't this work? How else can I approach this problem?

$ alias ,,=..
$ cd ,,
-bash: cd: ,,: No such file or directory

kilojoules

Posted 2017-04-27T17:25:54.780

Reputation: 590

6An alias is a program to run, not an argument to the program; so $ ,, would complain, as such: bash: ..: Is a directory. (In other words, it's not an executable.) – jpaugh – 2017-04-27T21:58:18.573

5@jpaugh: A clearer way to say that is: alias expansion only happens on the first "word" of a command. So as you say, it only works for command names, not args. (And you couldn't even alias 'cd ,,'='cd ..'. Well, you could, but you'd have to run it as cd\ ,, to make it all one word.) – Peter Cordes – 2017-04-28T01:20:46.927

5Consider zsh. It has global aliases, so alias -g ,,=.. and cd ,, works as you expect it to. – muru – 2017-04-28T05:13:14.187

I have this: function c() { cd "${1-..}"; } It's just like cd but the default behavior (when no argument given) is to to the parent directory (instead of the home directory as for cd). – Lassi – 2017-04-28T06:09:53.540

1Lateral thinking: find / -type d -exec ln -s .. {}/,, \;... ;-) – Toby Speight – 2017-04-28T12:58:35.673

Note that it is possible that there is an actual directory called ,, (try mkdir ,,). – Federico Poloni – 2017-04-29T09:57:56.030

2Imho: don't do this. Using aliases to cover up typographic errors is a bad practice. Those errors can end up in copy-pasted code or screencasts. It won't work in other hosts or accounts. And such modification (depending on how it's implemented) could cause other, unexpected, difficult to debug errors. My suggestion: if you mistype a command, simply type it again ;-). – jjmontes – 2017-05-01T14:11:52.223

Answers

45

ZSH:

If you'r using zsh alias -g ,,=".." is what you need, but this will cause ",," to be expanded everywhere, not only when used with cd.

From man zshbuiltins:

If the -g flag is present, define a global alias; global aliases are expanded even if they do not occur in command position.

BASH:

If restricted to bash (as the question is tagged with ), read the following:

This is a pure-alias solution, as requested, however this will do more than required possibly frustrating the user (see the warning at the end of my post).

Quoting man bash:

If the last character of the alias value is a blank, then the next command word following the alias is also checked for alias expansion.

Therefore it's enough to alias cd with an extra space (to allow expanding of its next argument) and then alias ,, to ... See that

alias cd='cd '
alias ,,='..'

gives exactly what you need.

Note that this is correct not only for bash (and its alias implementation), but all POSIX-compilant shells. Quoting an example from man 1p alias (the manual does not describe this feature explicitly, only through an example):

  1. Set up nohup so that it can deal with an argument that is itself an alias name:

           alias nohup="nohup "
    

Warning: As @PeterCordes writes in his comment, it will automatically cause other aliases to expand when written after cd. It may require you to write cd \grep if you want to change directory to one named grep but your grep is an alias for grep --color=auto. Without the backslash, cd will report "too many arguments" error (you can't cd to two directories at once)!.

styrofoam fly

Posted 2017-04-27T17:25:54.780

Reputation: 1 746

22That's a clever but nasty hack. I wouldn't want to do that; too easy for that to accidentally bite you. e.g. if you have an alias for a command you commonly run, and you want to cd into a directory of its source code. Or other collisions between your aliases and common directory names. Like cd dr would expand to cd disown -r for me, with this alias. Anyway, much better to override builtin cd with a function for stuff like this, IMO. – Peter Cordes – 2017-04-28T01:31:19.670

8+1 for pure-alias solution (I learnt something). At the same time I agree with Peter's comment. Some kind of explicit warning should be added to your answer, I think. – Kamil Maciorowski – 2017-04-28T04:16:24.290

58

Aliases aren't meant to do this, but you can create a function called cd that is a wrapper for the real cd. This one works for me! Just put it into your .bash_profile or your profile file of choice.

cd () { if [ "$1" = ",," ]; then builtin cd ..; else builtin cd "$@"; fi; }

Or, with comments and pretty formatting:

cd ()
{
  if [ "$1" = ",," ]; then  # if first argument is ",,"...
    builtin cd ..           # call the builtin cd with ".." instead...
  else
    builtin cd "$@"         # else call builtin cd with original arguments 
  fi
}

EDIT

Thanks @derobert for pointing out that if then else is better here than && ||. Also, I just realized (*facepalm*) that this implementation will only work if any non-path arguments (i.e. -L -P) are not the first argument. So be warned, if you have a bad habit of typing cd -L ,, this isn't going to help you. And that is non-trivial to handle correctly, I think.

BenjiWiebe

Posted 2017-04-27T17:25:54.780

Reputation: 7 672

16@BenjiWiebe I think the "comments and pretty formatting" version would be better with an if-then-else. – zwol – 2017-04-27T19:42:36.513

Wow folks, lots of good ideas. I see you are using the edit feature to take care of the fixes needed. I didn't spend much time testing it. :) – BenjiWiebe – 2017-04-27T20:49:40.537

1Alternatively, just overwrite $1 before executing the built-in: cd () { [ "$1" = ",," ] && set .. ; cd "$@"; } – Toby Speight – 2017-04-28T07:42:08.907

1@TobySpeight set .. "${@:2}", or you lose anything after the first argument. – chepner – 2017-04-28T11:26:50.817

8Also, technically .. doesn't have to be the first argument; cd in bash can take a variety of options (-P, -L, -@, -e). – chepner – 2017-04-28T11:29:08.390

You need to use if here. Otherwise, you have a bug: if builtin cd .. fails, the || part will execute. That is a very uncommon occurrence, but it can happen (e.g., on an NFS mount). – derobert – 2017-05-04T19:06:47.137

@derobert I see your point and (kind of) agree, but this thing is for the occasional typo. So point 1) the chances of a typo and a rare NFS mount bug happening simultaneously are really slim, and 2) if you make a typo, an error is hardly surprising...and this would be the "original" error anyways of saying that no directory ",," exists. – BenjiWiebe – 2017-05-12T03:16:41.627

@derobert But the more I think of it, the less reason I see to leave it as-is. ;) – BenjiWiebe – 2017-05-12T03:17:14.710

@BenjiWiebe change it if for no other reason than someone might see it and think it's a valid if-then-else and use it somewhere where it matters. Examples should show good practices, not tricks that sort of work in a few limited use cases. – derobert – 2017-05-12T03:22:54.813

29

Aliases must be the first word of a command. Also, the alias must be substituted for a word therefore no spaces).

Bash Reference Manual: Aliases

Aliases allow a string to be substituted for a word when it is used as the first word of a simple command.

You could alias both .. and ,, to be cd ...

$ alias ..="cd .."
$ alias ,,="cd .."
$ cd /tmp && pwd
/tmp
$ ,, && pwd
/

Steven

Posted 2017-04-27T17:25:54.780

Reputation: 24 804

Thats exactly what I do! :D these two dots/commas are much easier to type than cd .. – rav_kr – 2017-04-27T19:42:57.503

10+1, that's not a bad idea at all. Another way to do it for .. in Bash is with shopt -s autocd which lets you change to any directory by just entering its name. Of course you still the alias for ,, – ilkkachu – 2017-04-27T19:52:22.007

Me too :-) – joeytwiddle – 2017-04-29T09:51:35.937

3

Another way to make .. change the directory is to enable Bash's autocd feature:

shopt -s autocd 

That'll automatically change the directory when you enter the name of one:

~$ /tmp
cd /tmp
/tmp$ 

You still have to make an alias for ,, but that can be done with just alias ,,=..

ilkkachu

Posted 2017-04-27T17:25:54.780

Reputation: 860

2

There's already an app a script for that: https://github.com/shyiko/commacd (no affiliation with Stanley Shuyiko).

commacd exports three commands: , (for jumping forward), ,, (backward) and ,,, (backward+forward):

All three of them try to match by prefix first. Only if no results are found, will they fallback to substring (fuzzy) matching

To answer your question the script aliases commas to three functions it defines:

alias ,=_commacd_forward
alias ,,=_commacd_backward
alias ,,,=_commacd_backward_forward

Doctor Dao

Posted 2017-04-27T17:25:54.780

Reputation: 29