17

I recently added

alias ..='cd ..'
alias ...='cd ../..'
alias ....='cd ../../..'

to my bash_aliases file. Playing around with this, I noticed that while aliasing .. was allowed, aliasing . was not. What other punctuation characters are allowed in bash aliases?

Boris Verkhovskiy
  • 14,854
  • 11
  • 100
  • 103
  • 4
    What version of `bash` are you using? I can alias `.` just fine. However, `.` is already defined as a command name in the POSIX specification, so you probably should not shadow it with an alias. – chepner Jul 11 '14 at 11:57

4 Answers4

8

It's always been safer to use functions instead:

function .. { cd '..'; }
function ... { cd '../..'; }
function .... { cd '../../..'; }

Or for a conservative preference:

..() { cd '..'; }
...() { cd '../..'; }
....() { cd '../../..'; }

What is safer about doing it this way?

Aliases affect first-class syntax (if, case, etc.) and its commands are specified using quotes. It's like having to use eval unnecessarily. Using functions on the other is straightforward and you know exactly how the arguments are expanded. TL;DR aliases are a hack. It's like using a #define statement in C when you can simply define a function. It's something beginners would love to compose.

If anyone would want to define default arguments to a command, you can use command to make the function call the external command to avoid recursion. That's the right way to do it. E.g. function grep { command grep --color=auto "$@"; }

konsolebox
  • 72,135
  • 12
  • 99
  • 105
7

Bash aliases definitely can't contain these characters: space , tab \t, newline \n, /, \, $, `, =, |, &, ;, (, ), <, >, ' and ".

The Bash Reference Manual says:

The characters /, $, `, = and any of the shell metacharacters or quoting characters listed above may not appear in an alias name.

"Shell metacharacters" are defined as

A character that, when unquoted, separates words. A metacharacter is a space, tab, newline, or one of the following characters: |, &, ;, (, ), <, or >.

"Quoting characters" aren't explicitly listed but they are the backslash \ and the single ' and double " quotes.

Bash checks alias names in legal_alias_name() which is implemented here: 1, 2, 3. Looking through the output of mksyntax.c (a C program that generates another C program) on my system, shellbreak() will return true for these 10 characters: \t\n &();<>|, shellxquote() for these 4: "'\`, and shellexp() for $, finally legal_alias_name() also checks for /.

However, there are other limitations from 1) how Bash tokenizes the alias expression that you would have to write to define the alias and 2) how it will tokenize a command that starts with your alias. Namely, for 1), = can't appear in an alias name, probably because alias foo=bar=baz would be parsed as foo = bar=baz, not foo=bar = baz. For 2), from my experiments, you can define an alias with !, the history expansion character, but if you try to use it, you'll get a command not found error, unless the ! is at the end of the command. There's probably other characters, the safest bet is to stick to numbers, letters and the underscore.

Boris Verkhovskiy
  • 14,854
  • 11
  • 100
  • 103
  • 1
    For completeness: I use `!` in many of my "dangerous" commands (like force push `gpf!` or interactive rebase `gri!`), but only as the final character. Not sure if they work in other locations in the alias name. Came to this thread looking to see how else I might use `!` :) – Xunnamius Dec 08 '20 at 22:08
  • 1
    @Xunnamius `alias "abc!"=echo` works but `alias "a!bc"=echo` and `alias "a\!bc"=echo` and `alias "!abc"=echo` don't. – Boris Verkhovskiy Dec 08 '20 at 23:07
4

According to the following environment variables names can only contain

uppercase letters, digits, and the '_' (underscore) from the characters defined in Portable Character Set and do not begin with a digit. Other characters may be permitted by an implementation; applications shall tolerate the presence of such names.

But variables are not really the same the same of alias names.

In practice a -(dash) should be added to the list because it is a defacto standard in debian(apt-get). In addition _~@#%^., all work and ><'"|=()`/?[]+!. don't. In addition you have to worry about $PATH and characters like :. It appears space and linebreaks could work if they are properly escaped or quoted like so "a b".

Quelklef
  • 1,999
  • 2
  • 22
  • 37
Lime
  • 13,400
  • 11
  • 56
  • 88
  • 1
    I tried to use a `/` in my alias name but it didn't work. – Andrew Jan 27 '18 at 00:09
  • 3
    The GNU [manual for bash](https://www.gnu.org/software/bash/manual/html_node/Aliases.html) says "The characters `/`, `$`, `\``, `=` and any of the shell metacharacters or quoting characters listed above may not appear in an alias name." so this answer (which says `/` and `$` are okay) is wrong. – Boris Verkhovskiy Nov 17 '19 at 00:10
1

https://www.gnu.org/software/bash/manual/html_node/Aliases.html I wouldn't name an alias .. in linux . is a special name for the current director and .. is for the parent directory. there could be some obscure process that could be screwed up by aliasing .. for cd

DTSCode
  • 1,062
  • 9
  • 24
  • 2
    `..` is just a (special) directory name, so syntactically it's no different than something like `foobar`. – chepner Jul 11 '14 at 11:56
  • im aware, and normally it wouldnt matter, but if you put it in bashrc, and some system tries to execute it and instead cd's to it, then it will be weird, which is why as konsolebox said, functions are safer – DTSCode Jul 11 '14 at 15:44
  • 3
    The problems you describe are the same whether you define `..` as an alias or a function, but neither would be invoked if `..` were used as the argument to a command. Since `.bashrc` is only invoked for interactive shells, there's no worry that you will change the behavior of any shell script, especially system scripts (as long as you don't mess with `/etc/bashrc`, since they scripts will run as `root`, not a user account). – chepner Jul 11 '14 at 15:58
  • 1
    ah ok i see what you mean – DTSCode Jul 11 '14 at 16:15