Tabla de Contenidos

BASH tips and snippets

This page documents bash tips and snippets that I typically use in my shell scripts. I keep them together to be able to quickly check them if required.


Colours in prompt

In your .bashrc file:

export BLACK="\[\e[00;30m\]"
export BLUE="\[\e[00;34m\]"
export GREEN="\[\e[00;32m\]"
export CYAN="\[\e[00;36m\]"
export RED="\[\e[00;31m\]"
export PURPLE="\[\e[00;35m\]"
export BROWN="\[\e[00;33m\]"
export GRAY="\[\e[01;30m\]"
export L_GRAY="\[\e[00;37m\]"
export L_BLUE="\[\e[01;34m\]"
export L_GREEN="\[\e[01;32m\]"
export L_CYAN="\[\e[01;36m\]"
export L_RED="\[\e[01;31m\]"
export L_PURPLE="\[\e[01;35m\]"
export L_YELLOW="\[\e[01;33m\]"
export L_WHITE="\[\e[01;37m\]"
export NORMAL="\[\e[00m\]"
 
# Red prompt for root
export PS1="${L_RED}\u@\H:${BLUE} \w #${NORMAL} "
 
# For a normal user, use this instead:
#export PS1="${L_YELLOW}\u@\H:${BLUE} \w \$${NORMAL} "


Check if variable starts or ends with substring

# SH
if [ "${HOST:0:4}" = "user" ]; then ...; fi
 
# BASH
if [[ "$HOST" =~ ^user.* ]]; then ... ; fi
 
# BASH (without quotes, for * to expand):
if [[ $HOST == user* ]]; then ... ; fi 


Get the last argument given to the script

LASTARG="${@: -1}"


Remove the last argument given to the script

set -- "${@:1:$(($#-1))}"


Use colours in bash scripts, with --nocolor option

This code allows to use colours in your scripts, and disable them giving –nocolor

# Terminal colours
RED="\e[31m"
YELLOW="\e[33m"
NORMAL="\e[0m"
GREEN="\e[92m"
 
# Disable terminal colours if "--nocolor" flag is passed as last argument:
LASTARG="${@: -1}"
if [ "${LASTARG}" == "--nocolor" ];
then
    RED=""
    YELLOW=""
    NORMAL=""
    GREEN=""
fi
 
# Now you can safely write colors with:
echo -e "* File $FILE ${YELLOW}already patched${NORMAL} ${GREEN}[success]${NORMAL}\n"


Remove trailing bar in argument if exists

Sometimes our scripts accept paths as command line arguments. As we don't know if the user will add a trailing bar to the path (/tmp or /tmp/), we can use bash's % operator to remove it:

# Remove trailing / from $1 (if it ends with a /).
DESTDIR="${1%/}"
 
# Another example:
BACKUPDIR="${BACKUPDIR%/}"


Request a password with visual feedbackup

unset MYPWD
prompt="Please insert the password: "
while IFS= read -p "$prompt" -r -s -n 1 char
do
    if [[ $char == $'\0' ]]
    then
        break
    fi
    prompt='*'
    MYPWD+="$char"
done
echo


Trap CTRL+C and KILL to remove tempfiles

We should always remove temporary files created with mktemp. But if our script it's killed with CTRL+C or with kill, the temporary file won't be deleted. Bash provides a signal trapping mechanism to allow us to minimize this effect:

TEMPFILE=$(mktemp)
trap "rm -f ${TEMPFILE}; exit 1" INT TERM
 
   (your code...)
 
rm -f $TEMPFILE
trap - INT TERM

Note that there is a small race condition between the tempfile creation and the trap command (the file is created and the trap is not yet set).


Vi mode for bash (readline)

By setting "set -o vi" in our .bashrc file (or typing it directly in the terminal), we change from "emacs-mode" to "vi-mode" (check set -o). While in Vi mode, we can use the Vi keyboard commands to work in the terminal. Each command starts in insert mode but we can go to command mode by pressing ESC.

In your .bashrc:

export VISUAL=/usr/bin/vim
export EDITOR=/usr/bin/vim
set -o vi

Now, in command mode, the following Vi keys/commands will act as expected:

Specially useful commands are included:

Searches also work like in vi:


Recall last argument from the last command

Unfortunately, with the vi mode I lost the only "emacs" command that I typically used: ESC + . (to recover the last argument from the previous command). To solve this, we have a couple of alternatives:

First: you can use bash's !$ or $_ but it is not expanded until you execute the command and it's quite dangerous used that way.

Second: you can use Alt+. instead (which also works in emacs mode) by adding the following to your ~/.inputrc file:

set editing-mode vi
set keymap vi-insert

$if mode=vi
   "\e.":yank-last-arg
$endif

Then, edit your ~/.bashrc and after the set -o vi add:

if [[ $- =~ i ]] && [[ -f ~/.inputrc ]]; then
    bind -f ~/.inputrc
fi

If you don't mind losing Vi's dot (.) functionality, you can also add the following to your .inputrc file:

set keymap vi-command
$if mode=vi
    ".":insert-last-argument
$endif

Finally, another option would be to switch to command mode and press _ (underscore): ESC + _.


Block arrow keys in command mode

If you also want to "block" the arrow keys in command mode, add the following in your .inputrc file:

set keymap vi-command

$if mode=vi
   "\eOD":""
   "\e[D":""
   "\eOC":""
   "\e[C":""
   "\eOA":""
   "\e[A":""
   "\eOB":""
   "\e[B":""
$endif


Other emacs-mode typical shortcuts in vi mode

If we are used also to other emacs shortcuts like "Clear the Screen" (Ctrl+L) or "Home" / "End" (Ctrl+A and Ctrl+E) we can add them to our .inputrc file:

set editing-mode vi
set keymap vi-insert

$if mode=vi
(...)
   "\C-l":clear-screen
   "\C-a":beginning-of-line
   "\C-e":end-of-line
   "\C-w":backward-kill-word
$endif

set keymap vi-command
$if mode=vi
(...)
   "\C-l":clear-screen
   "\C-a":beginning-of-line
   "\C-e":end-of-line
   "\C-w":backward-kill-word
$endif


<Volver a la sección de GNU/Linux>