Quickshiftin - Clever Crazy Code

BASH vs ‘Proper’ scripting languages

December 17th, 2014

Lately I’ve had the chance to dive much deeper into BASH than I ever have before. I’m working on a build system with a dozen or so library files, and as many client scripts for the actual builds. A big question is whether or not BASH is the best language for the system compared to scripting options like Python, Perl, Ruby, PHP >cough<, etc. Initially I wrote the entire build system in BASH. But given an opportunity to learn Python, and put the theory to the test, I decided to start implementing some of the components in Python to see what it could offer.

Strengths and weaknesses

Calling other programs, BASH is king

I wasn’t always good at BASH. For years I’ve been writing PHP and once I was good enough realized I could write all my ‘CLI’ programs with PHP. I was super excited and well, I have written a ton of Cron jobs, image processing code and more in PHP. It works great, but there’s a big aspect I don’t care for that can be said of any of the alternatives too. Building commands for the shell, then running them through a function like shell_exec or exec etc (or something similar from another language) becomes tedious. I’ve got a neat comparison to show you soon, but before going on, I want you to glance at this one-liner I put together during a server migration. This searches through all the available vhost files for log file definitions, forms a unique list and creates the files on the filesystem. Seriously, even though you could write this in another language would you ever want to? The brevity of this code is the magic of BASH.

#------------------------------------------------------------
# Read Apache Vhost configuration files,
# and initialize the log files they define
#------------------------------------------------------------
egrep -i '(access|error)' /etc/apache2/sites-available/* | \
grep '/var/log/apache2' | sed -E 's/^.*(\/var\/log.*.log).*$/\1/g' | \
sort | uniq | sudo xargs touch

OK, onto the comparison; here’s a trivial script that runs the Imagemagick convert program on a file to strip its RGB color profile. The first version is in BASH, then there are two more implementations in PHP and Python. Compare the programs esthetically, which looks the easiest on your eyes? If you’re like me, you’ll agree it’s BASH! It’s certainly the shortest implementation. Ironically, BASH is typically criticized for being ugly.

BASH

#!/bin/bash
#------------------------------------------------------------
# Strip the RGB color profile from an image
#------------------------------------------------------------
if [ $# -ne 1 ]; then
  echo 'Usage: strip-profile '
  exit 1
fi

file="$1"
if [ ! -f "$file" ]; then
  echo 'Usage: strip-profile '
  exit 2
fi

convert "$file" -strip "$file" 2>&1

PHP

#!/usr/bin/php
<?php
//------------------------------------------------------------
// Strip the RGB color profile from an image
//------------------------------------------------------------
if($argc != 2) {
  echo "Usage: strip-profile \n";
  exit(1);
}

$file = $argv&#91;1&#93;;
if(!file_exists($file)) {
  echo "Usage: strip-profile \n";
  exit(2);
}

$escaped_file = escapeshellarg($file);
exec('convert ' . $escaped_file .
     ' -strip ' . $escaped_file . ' 2>&1',
     $output,
     $return);

$output = implode("\n", $output);
if(!empty($output))
  echo $output, "\n";
exit($return);

Python

#!/usr/bin/python
#------------------------------------------------------------
# Strip the RGB color profile from an image
#------------------------------------------------------------
import sys
import os.path
import subprocess

numArgs = len(sys.argv)
if numArgs != 2:
    print 'Usage: strip-profile '
    exit(1)

file = sys.argv[1]
if not os.path.isfile(file):
    print 'Usage: strip-profile '
    exit(2)

cmd          = ['convert', file, '-strip', file]
proc         = subprocess.Popen(cmd, stdout=subprocess.PIPE)
responseCode = proc.wait()
stdOut       = proc.stdout.read().strip()

if len(stdOut) > 0:
    print stdOut
exit(responseCode)