How to easily make an alias command permanent? [duplicate]
Solution 1:
There is no bash builtin to add permanent aliases. Such aliases are created by adding them to a configuration file that is sourced by interactive shells, as you've done with .bashrc
.
But you might consider modifying your palias()
implementation by making it put the aliases in a separate file. I think this may be considered an improvement, for six reasons:
The file that is mostly edited automatically can be separate from the file that is mostly edited manually. If you need to see what has happened--out of curiosity, or to investigate a problem--this separation may be helpful. (Or if the function is accidentally called many times, creating a large number of unnecessary lines, the damage will be somewhat more contained.)
By putting the individual, automatically generated alias definitions elsewhere than
.bashrc
, you create a system that "works behind the scenes," which is often what people want when they look for a dedicated builtin to perform a task..bashrc
is already usually quite complicated. It will be easier to read and modify for unrelated purposes if it's not filled with many user-defined automatically appended aliases.Simple implementations of
palias()
-- including what you've written and what I'm about to recommend -- will create bad lines if the file they're appending to is not already newline-terminated (or blank). Normally text editors do this for you but it's possible to accidentally end a text file without a newline, in which casepalias()
will create a munged-together line that may or may not be correct, and which either way would be very difficult to read. By putting aliases in a separate file that you rarely, or at least less frequently, edit manually, you decrease the risk of this.If you ever expand your
palias()
implementation to read the existing contents of its target file, for example, to give useful warnings, it may be much easier to do so if can be assumed to consist entirely of alias definitions. (Or, for more sophisticated parsing: entirely of alias definitions and lines assumed to be wrong.)-
It is already widely suggested (though admittedly not as any sort of strong admonition) to put new aliases in a separate file:
.bash_aliases
See How do I create a permanent Bash alias? for more information about places to put aliases.
Default .bashrc
files in Ubuntu contain the code:
# Alias definitions.
# You may want to put all your additions into a separate file like
# ~/.bash_aliases, instead of adding them here directly.
# See /usr/share/doc/bash-doc/examples in the bash-doc package.
if [ -f ~/.bash_aliases ]; then
. ~/.bash_aliases
fi
Thus if you create .bash_aliases
, it will be used. The command to define the palias()
function can then be:
palias() { echo "alias $1='$2'" >> ~/.bash_aliases; }
That command should still go in .bashrc
, but the aliases it creates will be placed in .bash_aliases
.
More sophisticated implementations are possible. You could:
-
Run the definition as well as adding it, so it's immediately usable. This is suggested in osirisgothra's answer. I'd use:
palias() { echo "alias $1='$2'" >> ~/.bash_aliases; alias "$1=$2"; }
-
Check to ensure
.bash_aliases
is nonexistent, empty, or newline-terminated, and if it is nonempty but not newline-terminated, append a newline prior to the alias definition.palias() { local target=~/.bash_aliases [[ -f "$target" && -n $(tail -c1 "$target") ]] && echo >> "$target" echo "alias $1='$2'" >> "$target" }
See Gilles's answer to Add missing newlines in multiple files for details on detecting missing newlines with
tail
. -
Check and warn about defining an alias that has already been defined in
.bash_aliases
.Ploutox suggested that idea. But I do not recommend using
grep $1 ~/.bash_aliases
or similar, because it will produce frequent false positives, anytime$1
matches any part of another alias's definition, and occasional false negatives. The matter is further complicated by how some valid bash aliases, taken as regular expressions, match more than themselves--+
and.
actually get used in command and alias names--and a few don't match even themselves.grep "alias $1="
is better but mitigates the problem only partially. A leading^
in the pattern would pretty well match only the leadingalias name
of a definition, but not address the problem of regexp metacharacters in$1
, while usinggrep -F
would strip all metacharacters of their special meaning but in doing so prevent^
from being used.grep
ing.bashrc
in this way is even worse than.bash_aliases
, as there's an essentially unlimited variety of text that may be part of that file, mostly outside any alias definitions.If you want to check for aliases that are defined in the current shell, whether or not they're written in
.bash_aliases
(or anywhere), you can usealias "$1"
(or runalias
with no arguments and match, carefully, against its output). Credit goes to muru for this idea. It does have the disadvantage that if you define an alias withalias
to test it out and then make it permanent withpalias
, you'll get a warning even though it was not yet permanent and everything is fine.To check new permanent aliases against the contents of
.bash_aliases
, you could do something like this:palias() { local target=~/.bash_aliases if grep -Pqs '^[ \t]*alias[ \t]+\Q'"$1"'\E\=' "$target"; then printf "%s: %s: warning: defining \`%s' again in %s\n" \ "$0" "$FUNCNAME" "$1" "$target" >&2 fi echo "alias $1='$2'" >> "$target" }
That seems to work well, though I suspect there are more elegant ways. (Arguably
[ \t]*
should be removed, if you take leading whitespace beforealias
as a suggestion that it is part of a multiline alias definition.) It will malfunction if\E
appears in$1
, but shell metacharacters and quoting characters like\
aren't valid in alias names, so you won't need to give that as input.
Ideally, on any wrong input, any user-facing function you call would perform no operation except printing a useful error message. But by the nature ofpalias()
, at least unless you're prepared to make its definition far more sophisticated (see below), the burden of reasonable input already falls mostly on the user. You can write non-aliases and alias definition syntax errors to.bash_aliases
with this function, and while that's probably acceptable given the way you'll be usingpalias()
, choking on\E
is minor in comparison.More seriously,
alias name1='def1' name2='def2' ...
is perfectly good syntax for thealias
command, but I haven't tried to parse out alias definitions given as subsequent arguments toalias
in.bash_aliases
, as I believe correctly determining where the first non-quoted blank occurs would be non-trivial.Therefore, if you use the above
palias()
implementation and also sometimes manually define aliases in.bash_aliases
(or whatever file you use as$target
), you should define just one alias peralias ...
line if you want to have reliable warning behavior.
It will also fail to recognize alias definitions to the right of a;
or other connectives, for example to chain separatealias
commands on the same line, but it seems unlikely you'd want to do that in.bash_aliases
. Parse
$1
to ensure it is a valid name for an alias.Parse
$2
to attempt to figure out if it is a plausible body for an alias, and if it is not, then warn, fail, or (where applicable) quote it properly. For example, what happens if a'
character appears in$2
?Do a simpler version of that instead, just checking for and addressing
'
in$2
.
But you likely don't want to bother with any of that. You know how your function works, its limitations, and how to use it properly. I see four options for you that are at the same time reasonably good and pretty simple:
- Just keep using what you have now.
- Use an implementation as above, putting the aliases in
.bash_aliases
instead of.bashrc
. - Make a third file for automatically added aliases, and source that file separately (either in
.bashrc
or.bash_alises
. - Don't use a
palias()
function at all, and just manually add aliases by editing.bash_aliases
or.bashrc
.
Solution 2:
I suggest (of course you don't have to) putting an eval "$_"
after the echo
command, so the alias is added right away, and a grep -Pq "alias $1" && return
at the start, to make sure that (1) you don't have duplicate alias names, (2) aliases get defined right away instead of waiting for them to be re-sourced.
If you want to get even more creative (this is how I do it), also allow it to take a number from your history, and define it as an alias, or a group of numbers assigned in sequence to one alias, or more, etc.
I've put quite a lot of work into my own .bashrc over the years -- I do share it under a project called gxbase, but since it is "my preferences" it most likely is not what "other people" want. Configuration settings are a very personal thing. Most people expect things to look like /etc/skel/.bashrc
, and stuff like bash completion stops working if you set too many custom options :) Just for fun though, my link is http://gitorious.org/gxbase. The file is in extras/my.bashrc/*
(see PS at bottom if interested).
As for your question, there are many people out there who post their so-called 'ultimate .bashrc settings' but alas they are only ultimate for them, my answer is: you will be happiest if you create this file yourself, and believe me, for the love of all that's holy; make [offline] backups!!! :) A 'hard (printed) copy' is a good way to plan it further if you want to get even more creative!
PS: The contents of .bashrc-git are a fork from the gitsh project, so most of the credit for that one goes to that guy, and the perlconsole & aptsh integration also are not mine (entirely). You'll have to install the modded perlconsole & aptsh files to get that fully integrated into virtual directories.