Nifty bash scripting

One of the things I should do more often is to read the man pages. Recently I have spent some time digging into the bash man pages, and I would like to share some interesting stuff.


If you run a script, it looks for this variable and if it’s set, expands the value to the name of a file and reads its content. The filename should content the absolute pathmane otherwise it will no be able to locate the file.

export BASH_ENV="$HOME/.customs"

Take a look to the above example. From now, and beacuse I set BASH_ENV in my .bashrc, my scripts will have a set of fuctions or whatever I defined in there. It would be the same doing source $HOME/.customs in every script. This is really good, you have a set of custom functions or variables available to all your scripts.

A good idea would be to set this variable in either /etc/profile or /etc/bash.bashrc , if you want to share it with the rest of users in the system.

2.Run in a subshell ( ) vs current shell{ }

This is someting you might not pay attention. In order to assign the ouput of some shell commands to a variable, try first to use { }. Let’s see an example:

# Current shell
declare -A colors=();

{ for key in ${!colors[@]}; do line+="$key" ; done; }

# Subshell
$(for key in ${!colors[@]}; do line+="$key" ; done;)

Perhaps you realized the problem it crops up here.

**Current shell {} **

-Variables are available while the script is running. In the previus example I can access both variables, colors and line. Commands are separated by ‘;’. It’s also quite handy when using conditionals.

 if_true  &&  { cmd1; cmd2; cmd3; }

**Subshell $() **

-Variable assigments do not remain. Any change to any variable in the script would not take effect after ending the command execution. However it would be possible to get the output by means of either echo or printf commands. Besides variable scope, performance could be worse due to new subshell execution.

3.Using [[ ]] expressions

You might know the old form ** [ ] ** , but this is the new one, and has some pretty cool properties as Pattern Matching. I guess the best way to get an idea is watching an example.

[[ $ip_address =~ ^([0-9]{1,3})\.([0-9]{1,3})\.([0-9]{1,3})\.([0-9]{1,3})$ ]] && echo "Valid IP address"

# Iterating matches
for n in ${BASH_REMATCH[@]}; do echo $n; done

Of course the above example is just for purpose, actually it does not validate a real ip address, but does the trick. Most interesting is the variable BASH_REMATCH, an array holding each substring matched by parenthesized subexpressions. Regarding regular expressions you should look for in the man as in regex(3) and regex(7).

4. Case and ;& operator

This operator continues the execution to next option if available. I came up with an example and you will see how it works:

while getopts $options  flag
    case $flag in
            [ $list_all == "on" ]  && shift
            [ $list_all == "off" ] && shift && shift

            if [ $list_all == "on" ];then
                for color in ${!colors[@]}
                    draw_with_color "$color" "$msg"
                check_color "$c" && draw_with_color "$c" "$msg"

            printf 'Available colors: \n'
            _show_colors && exit
            usage && exit
            usage && exit

Previus chunk of code is part of the pickcolor script. The main idea was to jazz some text up with a chosen color, then I thought it would be more practical to enable the option of pating the same text with all the available colors.
usage: [OPTIONS] message
       -a --all    Test all colors for message
       -c --color  Set font color.
       -l --list   List available colors.
       -h --help   Help

# Colors up using all the colors
$ pickcolor -a  Show me the colors

# Color up using just one color
$ pickcolor -c red Paint my room !!

The special operator ;& was really useful and did the trick. Next part I will write about shell vars and some builtin commands to have in mind.