10 Tips for Writing Efficient Bash Scripts

Bash is the default command line interface for many Linux distributions and a powerful scripting language. Here are some suggestions that will keep your Bash scripts efficient and lean. Feel free to comment with your own suggestions.

  1. Avoid Full Paths to Bash Builtins

    Bash has many builtins that can be used instead of calling external commands. You should leverage the builtin commands whenever possible since it avoids calling a subcommand from the system.

    Since Bash has builtins for some commands found in /bin and /usr/bin (such as echo), avoid using the full path for these commands and the builtin will be used.

    # avoid this
    /bin/echo "hello"

    Use the Bash builtin instead:

    echo "hello"

    Other bash builtins include: test, read, declare, eval, let pushd and popd. See the Bash man page for a full listing of builtins.

  2. Avoid External Commands for Integer Math

    Bash also provides builtins that can be used for integer arithmetic. Only use /usr/bin/bc if you need to do floating point arithmetic. Integer calculations can be made with these Bash builtins:

    four=$(( 2 + 2 ))
    four=$[ 2 + 2 ]
    let four="2 + 2"

  3. Avoid using Cat

    Tools like Grep, Awk and Sed will take files as arguments. There is rarely a need to use /bin/cat. For instance, the following is unnecessary:

    # avoid this
    cat /etc/hosts | grep localhost

    Instead, use Grep's native ability to read files:

    grep localhost /etc/hosts

  4. Avoid Piping Grep to Awk

    If using Awk, you can often eliminate the need for grep. Try not to pipe Grep to Awk:

    # avoid this
    grep error /var/log/messages | awk '{ print $4 }'

    Use Awk's native ability to parse text and save yourself a command.

    awk '/error/ { print $4 }' /var/log/messages

  5. Avoid Piping Sed to Sed

    Sed can take more than one command in a single execution. Avoid piping sed to sed.

    # avoid this
    sed 's/hello/goodbye/g' filename | sed 's/monday/friday/g'

    Instead, use sed -e or delimit the sed expressions with a semicolon (;)

    sed -e 's/hello/goodbye/g' -e 's/monday/friday/g' filename
    sed -e 's/hello/goodbye/g; s/monday/friday/g' filename

  6. Use Double Brackets for Compound and Regex Tests

    The [ or test builtins can be used to test expressions, but the [[ builtin operator additionally provides compound commands and regular expression matching.

    if [[ expression1 || expression2 ]]; then do_something; fi
    if [[ string =~ regex ]]; then do_something; fi

  7. Use Functions for Repetitive Tasks

    Break your script up into pieces and use functions to conduct repetitive tasks. Functions can be declared like so:

    function_name() {
      do_something
      return $?
    }

    Make your functions usable by more than one shell script by sourcing a functions file from the various scripts. You can source another file in Bash using the . builtin.

    #!/bin/bash
    . /path/to/shared_functions

    See the Bash man page, or my article on Bash functions for more information.

  8. Use Arrays Instead of Multiple Variables

    Bash arrays are very powerful. Avoid using unnecessary variables:

    # avoid this
    color1='Blue'
    color2='Red'
    echo $color1
    echo $color2

    Instead, use Bash arrays.

    colors=('Blue' 'Red')
    echo ${colors[0]}
    echo ${colors[1]}

    Check out my article on Bash arrays for more details.

  9. Use /bin/mktemp to Create Temp Files

    Need a temporary file? Use /bin/mktemp to create temporary files or folders.

    tempfile=$(/bin/mktemp)
    tempdir=$(/bin/mktemp -d)

  10. Use /bin/egrep or /bin/sed for Regex Pattern Matching

    Think you need Perl? Check out Sed or Egrep (grep -e) for regex pattern matching.

    # grep for localhost or 127.0.0.1 in /etc/hosts
    egrep 'localhost|127\.0\.0\.1' /etc/hosts
     
    # print pattern localhost.* in /etc/hosts
    sed -n 's/localhost.*/&/p' /etc/hosts


Comments

These are definitely some

These are definitely some great tips. Your knowledge of this is so good. Thanks for the info.
fort lauderdale auto accident attorney

href="http://www.replicahandb

href="http://www.replicahandbagsone.com/louis-vuitton-handbags-c-17.html">Louis Vuitton Replica Handbags are lower than the real one.
Tom open a GUCCI Handbags store, but he usually sale the GUCCI Replica Handbags, all the replica GUCCI Handbags are 80% off on sale, so many fashion women like to buying fake GUCCI Handbags in there.
Chanel Handbags are the famous world brand, so the replica Chanel Handbags shops are open all over the world, you never tell out the different from the chanel bags.
Macdonad love the Prada Handbags, she offen join the big exhibitions through the cities, but one day she buy one replica Prada Handbags, and go to a big party, all the women in there can not recognise this fake Prada Handbags, so in the end, when she tell them about the Prada replica Handbags, the whole party shocked.
Fashion Miu Miu Handbgs are very popular among the young women, because the high price of Miu Miu replica Handbgs, so many of them go to the replica Miu Miu Handbgs stores and buy the fake Miu Miu Handbgs as a lowest price.

I like this stuff! Writing

tiffany jewelry Choose, buy

tiffany jewelry
Choose, buy and shop for on sale tiffany jewelry including Tiffany & Co Silver Necklace, Pendants, Bangles, Bracelets, Earrings, Rings and Accessories.
tiffany co
Tiffany Jewellery offering bangle Jewellery, bracelet jewelry, eardrop jewelry, necklace jewelry, ring jewelry, finger ring jewelry and earring jewelry
tiffany
tiffany and co
links of london
links london
Tiffany Style Silver Jewelry: Rings, Earrings, Necklaces, Bracelets and more Tiffany Jewellery at low prices.

always provide GUCCI Replica

always provide GUCCI Replica Handbags, and all kinds of replica GUCCI Handbags lower price for sale, the more fake GUCCI Handbags you choose, the cheaper price you get.
As everyone knows that the Chanel Handbags are popular in the whole world, sell replica Chanel Handbags can get more profit, many people like to sell chanel bags because fashion women love them.
Taking the Prada Handbags to join the big party can show women's fashion, so even the poor people like to buy replica Prada Handbags, so when you walk on the road, you never surprised by so much fake Prada Handbags, do you feel have a Prada replica Handbags is a cool action?

Sometimes you can do without

Sometimes you can do without xargs:

find ~/Desktop -type f -print0 | xargs -0 tar -zcf files.tar.gz

find ~/Desktop -type f -print0 | tar --null --no-recursion -zcf files.tar.gz --files-from -

http://codesnippets.joyent.com/posts/show/1962

Stop using "wc -l" in

Stop using "wc -l" in conjunction with grep, e.g.: grep ... | wc -l

Instead use: grep -c ...

in #10, the substitute in

in #10, the substitute in the sed command is inefficient. try:

sed -n '/localhost.*/p' /etc/hosts

Wow. As a non-techie who's

Wow. As a non-techie who's been piddling around with shell scripts for a few years, this is just about the best freaking collection of tips I ever saw!

Thats good stuff for someone

Thats good stuff for someone who is starting learn bash scripts. I could imagine that is would be a good idea to show this page to my prof at the uni ;-)....

Very nice collection. But it

Very nice collection. But it looks like tip #9 violates tip #1. :p

@flint >>...But it looks

@flint

>>...But it looks like tip #9 violates tip #1. :p

Actually mktemp is not a bash builtin so the post is accurate. You can verify this by typing "builtins".

-Wil Moore III

Good tips thanks. For

Good tips thanks. For general scripting tips along the same lines but not bash specific, see: common shell script mistakes

While you should always

While you should always avoid changing your working directory in a shell script, if you must do so, use pushd and popd. That way, you don't have to explicitly save the current path to a variable to return to it later. (Handy on the command line too.)

Parenthesis.... Actually, it

Parenthesis....

Actually, it is much easier to use parenthesis.

That is,

pwd
( cd /tmp/; pwd )
pwd # the directory is back to the original location

Along the same line...

Along the same line... (find)

Some other optimization that saves a lot of extra shell is the use of the handy "xargs" command (especially in find) :

For instance, instead of doing a
find dir -type f -exec grep pattern "{}" \;
there is a much more optimized way of regrouping all the individual grep into one :
find dir -type f | xargs grep pattern

In terms of performance, that means running a few grep in a subshell (depending of the number of files) instead of 1 subshell +1 grep per file (the benefit increases as the number of files gets bigger)

The other nice "side effect" of the latter is that you also have filenames prepended before each matching which could also be accomplished in the 1st form by adding a second filename for each grep :
find dir -type f -exec grep pattern "{}" /dev/null \;

Check the find man page, it

Check the find man page, it provides the "+" -exec option in addition to the ";" one :)

You can also tell grep to print filenames with the -H option (again, check the man page).

No more YAUUOC please :-) #3

No more YAUUOC please :-)
#3 shows how to avoid YAUUOC's (yet another useless use of cat) but that is not restricted to commands like grep which handle filenames as a parameter :

for instance, tr which work from it's standard input can be used as followed :
tr pattern < file
instead of the "classical"
cat file | tr pattern

So, one thing to remember : cat is *NOT* a tool to print files onto the standard output (or pipe) but as it's name says : it is a way to concatenate files

> function_name() { >

> function_name() {
> do_something
> return $?
> }

In some cases, there is no need to return $?, because bash functions return exit status of the last executed command.

P.S. Your captcha is awful

If I'm not mistaken, you

If I'm not mistaken, you could also use:
sed 's/hello/goodbye/g;s/monday/friday/g' filename
instead of
sed -e 's/hello/goodbye/g' -e 's/monday/friday/g' filename

Very useful tips :-) One

Very useful tips :-)
One thing that I always do is use relative paths for stuff in user's home directory tree.
For example use:
~rizwan/shared/sandbox
rather than
/home/rizwan/shared/sandbox

There is also the Advanced

There is also the Advanced Bash Scripting Guide at http://tldp.org/LDP/abs/html/ that is under active development. It can even be purchased as a printed book.

Great tips! I didn't know

Great tips!
I didn't know sed could take more than one command with "-e".

Just use the semi-colon :)

Just use the semi-colon :)

this is very good stuff :-)

this is very good stuff :-)

Buy Essays Buy Research