7

I have read this thread about where to put aliases.

Now, let's suppose that my custom command is quite elaborate (takes arguments in input, is composed of several commands run one after the other, I want to preserve it multi-line for clarity's sake, involves quotes, double quotes, etc.), so I want to define it as a function, e.g.

sshdev_system_loop () {
        while true; do
          echo "[$(date +'%Y-%m-%d %H:%M:%S')] Trying to log into ststem $2 as user $1 ."
          timeout 10 ssh $1@$2
        done
}

shall I put it in .bash_aliases or at the end of .bashrc or in .profile?

On one hand I don't want to put it in .bash_aliases since it will "spoil" the list of

alias alias_name='command/list of commands'

and on the other hand, .bashrc looks like a file administrated by the OS, so I don't want to add things to it.

So what is the best practice to add functions as custom commands in Ubuntu?

Raffa
  • 32,237
Tms91
  • 365
  • ... of the three files, ~/.bashrc is what I would normally use for user defined functions. – Raffa Feb 23 '24 at 12:41
  • I don't see why you'd want to define an elaborate script as a loaded function. I have a ~/scripts directory that I add to my PATH in ~/.bashrc. If I added all the scripts as functions in ~/.bashrc, it would be a mess, and it wouldn't save any time. To display the contents of the ~/scripts directory, I type what on the command line to run a script. – Wastrel Feb 24 '24 at 15:16

2 Answers2

12

It is largely up to you and how you use your computer. bash_aliases is not a standard file, this is something Ubuntu adds to the system. If you look at Ubuntu's default .bashrc (/etc/skel/.bashrc), you will see:

if [ -f ~/.bash_aliases ]; then
    . ~/.bash_aliases
fi

Ubuntu sets itself up to source (read) that file (the . means read the file into the current shell) if it exists. So if you are planning to migrate your setup somewhere else, don't use bash_aliases at all.

If you only care about Ubuntu, then using bash_aliases or bashrc is the same thing. They will both be read at the same time since one sources the other, so the choice of which one to use is up to you.

That said, the .bashrc file is absolutely intended to be edited by the user and not to be administered by the OS, so you should feel free to edit it. Traditionally, you would put aliases and functions in ~/.profile, however, since .bashrc is read every time you start a new interactive non-login shell, while .profile is only read by interactive login shells. In practice, on a modern graphical system, that means that .bashrc (and .bash_aliases on Ubuntu) is read every time you open a new terminal, while .profile will be read only when you log in. So people would try to keep .bashrc streamlined so it wouldn't take too long to be read each time. However, on modern systems, it really doesn't make any noticeable difference. Our machines are fast enough to read larger files with no issue at all.

Another consideration is that .profile and .bashrc are read by different kinds of shell, login and non-login respectively as mentioned above. See my answers here and here for more details on this. The point is that on traditional systems, when running a non-login shell, .profile is not read. however, Ubuntu like its parent Debian, has a special line in its .profile that sources .bashrc:

$ grep -A1 bashrc /etc/skel/.profile 
    # include .bashrc if it exists
    if [ -f "$HOME/.bashrc" ]; then
    . "$HOME/.bashrc"
    fi

All this means that you can add functions to your .bashrc or .bash_aliases files as you like, and they will still be available to login shells. You might want to use .profile instead, but feel free to use .bashrc. That's what it's for: for the user to define extra stuff for their shell.

Some useful references:

terdon
  • 100,812
  • I would add, though, that semantically, .bash_aliases is intended to hold, well, aliases, not arbitrary shell code, so don't store functions there. You can just as easily add if [ -f "$HOME/.bash_functions" ]; then . "$HOME/.bash_functions; fi to .bashrc and have a dedicated place to store functions. (zsh does something similar, having an fpath variable that stores directories which contain files which are intended to be autoloaded to define functions.) – chepner Feb 23 '24 at 21:28
  • (Oh, I didn't notice that the other answer proposes the same thing.) – chepner Feb 23 '24 at 21:30
  • Regarding .bashrc being read for every new terminal, this makes it much more convenient to modify without having to log out and back in. – jpa Feb 24 '24 at 09:59
  • Also, .profile is used by all Bourne-style shells, including dash, ksh (and pdksh), bash in POSIX compatibility mode, ZSH in sh or ksh emulation mode, and probably some other shells I’m not thinking of right now. This means that using bash-specific syntax in .profile is likely to break things at some point. – Austin Hemmelgarn Feb 24 '24 at 13:07
8

A little twist on Terdon's excellent answer:

I've chosen the solution to add a new block to my .bashrc with the following contents:

if [[ -f ~/.bash_functions ]]
then
  . ~/.bash_functions
fi

As you can see, the principle is exactly the same as for .bash_aliases, except I prefer to have my functions defined in a separate file .bash_functions.

Then, there's yet another twist to it. When I define my function, I do it like this:

# Go up in directory structure
_up() {
  local d=""
  local limit="$1"

Default to limit of 1

if [ -z "$limit" ] || [ "$limit" -le 0 ]; then limit=1 fi

for ((i=1;i<=limit;i++)); do d="../$d" done

cd "$d" }

And then, I actually reference the function in my .bash_aliases file:

alias up='_up'

In that way, my function shows up in the alias list when I just run alias, but since it starts with _, I know it's a function that's defined in .bash_functions.

Artur Meinild
  • 26,018