Quickshiftin - Clever Crazy Code

BASH vs ‘Proper’ scripting languages

December 17th, 2014

Complex programs, ‘Proper’ languages are king

We’ve seen where BASH excels, now let’s turn the coin over. BASH has functions, a `source` builtin (since replaced by simply a dot `.`), and global variables to separate code into logical components, but it lacks classes and namespaces. You tend to write files of functions that share data through global or `local` variables. When it comes to library size, I think BASH will struggle to grow beyond a certain point. On the contrary though, people have written large programs with these same tools using C for years.

BASH has support for arrays, but the syntax is terse and in my opinion hard to remember. Here’s a BASH version of in_array , look at the notation on the highlighted lines.

#------------------------------------------------------------
# Helper functions for arrays
#------------------------------------------------------------
# Thanks patrik
# http://stackoverflow.com/questions/3685970/bash-check-if-an-array-contains-a-value
#
# @param search
# @param array
#
# @note array must be passed as "${array[@]}"
#
# @return 0 if search is in the array, 1 otherwise
function in_array
{
    if [ "$#" -lt 2 ]; then
      echo You must provide at least two parameters to in_array
      exit 1
    fi

    local e
    for e in "${@:2}"; do [[ "$e" == "$1" ]] && return 0; done
    return 1
}

I suppose it’s not an issue to lookup things when you need to though and frankly calling them terse is a matter of opinion. I constantly look up PHP functions, Python functions etc. What’s wrong with looking up the syntax on a BASH array operation?
One of the coolest features for writing larger bodies of code I stumbled onto in BASH is that local variables are visible to any functions invoked by the function that defines them. Take a look at this, maybe it’s something that will come in handy for you. This is a tool to share variables yet keep them out of the global space.

# Define localvar then call b which modifies it
function a
{
    local localvar=(hi)
    echo Array from a "'"${localvar[@]}"'"
    b
    echo Array after calling b "'"${localvar[@]}"'"
}

# Populate the localvar local variable defined in a
function b
{
    localvar=("${localvar[@]}" there)
}

Two heads are better than one

Sometimes things are just easier in BASH or a ‘Proper’ language

Each language will have respective strengths and weaknesses. We’ve just seen some areas where BASH is strong and others where ‘Proper’ languages are better. Sometimes though, there are random problems that are just difficult to implement in one language. Recently, I wanted a simple function that would take a string, and print a ‘banner’ around the top and bottom of the string, the same length as the string. I read about printf and the disaster that is echo in BASH. I was seriously considering a for loop to iterate X number of times printing a single character! In this case I decided to implement the solution in Python

#!/usr/bin/python
import sys

numArgs = len(sys.argv)

if numArgs < 2:
    print 'Usage: error-msg <message> [heavy]'
    exit(1)

heavy = False
if numArgs == 3:
    heavy = sys.argv[2]

msg    = sys.argv[1]
length = len(msg)
char   = '-'
if heavy:
    char = '='

print ''.center(length, char)
print msg
print ''.center(length, char)

exit(0)

I’ve implemented the script as an executable, which means this is available from BASH!

$ ./error-msg.py hi
--
hi
--

You see when I say it’s available from BASH that means we can wrap the python-based utility and make it transparent to other BASH code. So we can seamlessly leverage our more powerful languages from our BASH code.

function error_msg
{
  ./error-msg.py $1 $2
}

By this same token, any ‘Proper’ scripting language will be able to call BASH scripts which have been made into executables. I showed examples of this on the first page in PHP and Python. One thing to be careful about though is how much bi-directional lines get drawn between the flows in your code. I once worked for a company that had an enterprise system in PHP and Java. The problem was there weren’t very clear lines between the two, which lead to confusing implementations and long nights of debugging! The same danger is present in using BASH together with other scripting languages.

The point is, you can use multiple languages together and take the best of both worlds! You might have a PHP script that calls some heinous piped BASH one-liner, ahem, look to the first code sample in this article! Or you might go the other way round, like writing out some utility as a class in Python because it’s just easier to model the code that way, then tap into it with a corresponding set of flat functions in BASH.

Summary

At the end of the day there’s always tradeoffs between design decisions. Rarely is one choice entirely better or worse than another. The same is true when selecting a language or languages to implement a software system. It can be nice having everything in one language, because you only need to know that particular language. But somethings are simply said best a certain way, and sometimes that means, in a certain language.

Share

If you enjoyed this post please consider sharing it!

  • Twitter
  • LinkedIn
  • Facebook
  • Reddit
  • Digg

Leave a Response