Save time at the command line with shell aliases and functions

304

Author: Marco Fioretti

Familiarity with command prompts and shell scripts is still necessary if you want to get the most from your GNU/Linux system, but the less time you spend doing that the better, right? Two powerful ways to minimize your time at the command line are shell aliases and functions.

The examples that follow are for the bash shell, but all the concepts and most of the code are valid for other shells too.

Shell aliases are alternative, easy-to-remember names for long commands that you need to execute frequently. When you type at the command line, the shell first looks for what you wrote in its list of aliases. If it finds a match, it replaces the alias with its corresponding text; after that, it looks again at the whole resulting command line and executes it. Here are some examples of aliases definitions:

alias sqlmanage='mysql -p -u my_MySQL_userid MySQL_database_name' alias ssh2rws='ssh -p port_number my_remote_userid@my.remote.web.server' alias findbig='find . -type f -exec ls -s {} ; | sort -n -r | head -5' alias cof='clear;ls -lrt'

The first two replace the much longer strings one would need to connect to a local MySQL database and to a remote server. The third finds the five biggest files in the current directory tree. The last alias, while simpler and shorter than the others, is more flexible. Due to the way aliases are replaced, you could use “cof” to list any group of files or directories, oldest files first:

cof # clear screen, list content of current directory cof /tmp /usr # clear screen, list contents of /tmp and /usr cof *.jpg # clear screen, list all .jpg files in this folder

You can define aliases at the prompt during a shell session, but they’re more useful if you make them permanent by defining them inside your system or personal shell configuration file (/etc/bashrc or $HOME/.bashrc). To know which aliases are already defined in your shell, just type alias at the prompt.

As handy as they are, aliases have some limits and gotchas. To begin with, they are not expanded when the shell is not interactive, unless you set the proper options (see the bash man page). Also, the shell loads at least one complete line of input, then replaces aliases, and only after that executes the whole resulting command. This means that you can use more than one predefined alias in the same line, though this may have unpredictable results, but you cannot define an alias and then use it in the same line. For the same reason, bad things may happen if you try to define aliases inside shell functions. To stay on the safe side, never mix alias definitions with anything else in the same line: don’t use or define aliases in compound commands or code blocks executed only when some condition is met.

Beyond aliases: Shell functions

Aliases cannot replace blocks of similar but not identical codes. They cannot handle errors nor return custom exit codes, do flow control, or use variables. If you need to do any of these, it’s time to learn how to use shell functions.

Shell functions are code blocks structured as complete sub-scripts, written once and invoked from any script that needs it. There are two equivalent ways to declare a function in bash. The first uses the function keyword, while the second replaces it with parentheses:

function my_function { code } my_function () { code }

Whichever syntax you prefer, remember that the definition must precede the first call to the function. You can also nest a function within another function, or write recursive functions. Inside functions you can use pretty much any construct available in your shell of choice; what requires special care in the code of a function is how it interacts with the script that uses it.

A script can use a function only if it is defined and predeclared in the script itself, or if it was already known in the shell that launched it. You can create and load functions in at least four (conceptually) different ways. One is to just type them at the command line as you would inside a script. A permanent alternative is to save all your functions into one file and then load that file with the ‘.’ command from the command line or any script.

You can declare functions inline in the weirdest places: this shell prompt customization trick defines a function inside the shell prompt itself. You can even simulate different versions of a function that depend on other variables:

if [ "$USER" eq "root" ] then . /etc/root_only_functions.sh else . /etc/normal_users_functions.sh fi backup_all_files # depends on user

The backup_all_files function that will be executed will be the one written inside /etc/root_only_functions.sh if the script is run by root, and the one inside /etc/normal_users_functions.sh in all other cases. Beware: when a function is defined multiple times, the final version is the one that is invoked.

The arguments passed to a function are placed inside special variables named $1, $2, and so on. A special array called $@ contains all the input arguments. Limit yourself to using $1, $2, and so on only when your function has a fixed number of arguments. With functions whose number of arguments may change at every call, and with recursive functions, work on one parameter at a time instead, pulling each out from $@:

function partition_maintenance { for partition in $@ do #do something to the current partition done }

Return an exit status from all your functions, because it is useful for diagnostic purposes. To do so, use the return keyword:

function check_treshold { if [ $SOME_VAR -gt 40 ] ; then echo 5; return 5; else echo 4; return 4 ; fi }

Running a function like this will put 4 into the special $? shell variable if SOME_VAR is less than 40. Remember that you can return only numerical values. To return strings or arrays you must either echo the function result and assign it to a variable with backticks:

IS_SOME_VAR_LESS_THAN_40=`check_treshold`

or pass that variable by reference to the function, which will modify it with an eval statement:

function set_variable { eval "$1=$2" }

In this case, the command “set_variable WEBSITE linux.com” (note the absence of dollar signs!) will assign linux.com to $WEBSITE.

To become more productive with shell functions, you also need to know when not to use them. This simple shell script shows three different ways to make calculations without a function and one way not to do it:

#! /bin/bash MY_VAR=40 echo 0: $MY_VAR MY_VAR=`expr $MY_VAR - 10` echo 1: $MY_VAR MY_VAR=$(($MY_VAR + (5**2 /2))) echo 2: $MY_VAR let MY_VAR="$MY_VAR + 7" echo 3: $MY_VAR MY_VAR="$MY_VAR + 7" # this is a string assignment, not a calculation echo 4: $MY_VAR

The output shows that functions are great, but necessary for arithmetic only if you have to deal with long, constant series of formulas:

0: 40 1: 30 2: 42 3: 49 4: 49 + 7

Category:

  • Shell & CLI