Work the Shell

Considering Legacy UNIX/Linux Issues

Dave Taylor

Issue #242, June 2014

Updating his shell script book, Dave bumps into a legacy Solaris problem, which leads to all sorts of interesting solution paths and discussion.

Gah, so frustrating! Ten years ago I wrote a rather popular book called Wicked Cool Shell Scripts, and I'm working on a new edition—a Tenth Anniversary release. There are lots of new scripts, entirely new chapters and updates to the older stuff. Fortunately, Bash hasn't evolved that much in the last decade, so just about everything still works fine (although there are some scripts I'm now realizing can't handle spaces in filenames—something I talked about years ago in this very column).

But, there were problems when I pushed out the following script to my Google Plus followers (find me on G+ at profiles.google.com/d1taylor) and asked those that had access to a Linux or UNIX system to give it a quick run:

#!/bin/sh
# how many commands: count how many executable commands
#   are in your current PATH.

myPATH="$(echo $PATH | sed -e 's/ /~~/g' -e 's/:/ /g')"
count=0 ; nonex=0

for dirname in $myPATH ;  do
  directory="$(echo $dirname | sed 's/~~/ /g')"
  if [ -d "$directory" ] ; then
    for command in $(ls "$directory") ; do 
      if [ -x "$directory/$command" ] ; then
        count="$(( $count + 1 ))"
      else
        nonex="$(( $nonex + 1 ))"
      fi
    done
  fi
done
echo "$count commands, and $nonex entries that weren't \
   marked executable"
exit 0

It's simple enough really—I'm using sed to split the $PATH value into space-separated values, then the for loop to step through them one by one, counting how many entries are marked as executable (the -x test).

Of course, you have to take into account that there might be spaces in directory names within the PATH (like /User Applications/bin), so I also convert spaces to ~~ and then later in the for loop convert them back at the last possible moment. But that's not rocket science, just basic scripting.

Why test to see if the directory in the PATH is an actual directory (the -d test), you may ask? Because when people can add their own directories to the system PATH, it can get messy, and it's entirely possible that there is an entry that's not a valid directory. So that's just error management really. Perhaps an else echo "Error: Entry $directory isn't a directory?" would be a good addition.

In any case, I posted this script, and people ran it on various systems, reporting answers ranging from 1,100 to more than 3,000 executable commands in their PATH (Ubuntu 13.10). More than 3,000 commands? Sheesh! Except then there was my friend Chris who said:

Sun OS 5.8 The line “for command...” gives me this error “syntax error at line 10: '$' unexpected”.

That's this line in the script:

for dirname in $myPATH ;  do

Well, that's puzzling, because there's nothing particularly complicated in that statement. Perhaps it's the ; in the middle of the line? Still, a classic—useless—error message from the shell. A bit of digging, and it turns out that he had a different default login shell, and that /bin/sh in that version apparently wasn't linked to /bin/bash. Oops. We changed the first line to invoke the proper shell:

#!/bin/bash

And...it still didn't work:

The script ran, but it came back with this: “First RE may not be null”. The second line read, “0 commands, and 0 entries that weren't marked executable”. There are a lot of executable files in my path.

Well heck. Now what?

Running Solaris to Test the Script

The logical solution was to gain access to a system running Solaris (ideally SunOS 5.8, aka Solaris 8), but who the heck is running a Solaris system and can grant me external SSH access? The answer: no one I could find, which is why it's fortunate that I found a far better path: VirtualBox.

Free to download from Oracle (https://www.virtualbox.org/wiki/Downloads), VirtualBox is a virtualization system, creating a system within a system. Even better, it runs on Mac or Windows systems along with various flavors of Linux, offering the ability to install and run a full Solaris installation (or just about any other OS you're interested in testing) as an app.

If you've experimented with VMware or Parallels, you've already bumped into this technology, and it's very slick. In fact, I run Windows 8 Pro on my MacBook Pro using VMware Fusion, and it works astonishingly well in its own full-screen window. The down side is that VMware Fusion isn't free. But, VirtualBox is—nice.

Download and install it, then you can grab a free copy of SunOS 5.11 (aka Solaris 11.1) at www.oracle.com/technetwork/server-storage/solaris11/vmtemplates-vmvirtualbox-1949721.html.

Unpack the OS and double-click. It's automatically opened by VirtualBox, and with another click or two, you're running Solaris 11.1 and have the default window manager, GNOME, front and center, as shown in Figure 1.

Figure 1. Solaris 11.1 Running within VirtualBox, within Mac OS X

Now finally, I can open up an xterm and test the script within a Solaris environment. The easiest path? Tweak the VirtualBox config to share the clipboard with the parent operating system, and you simply can copy and paste it into a vi edit buffer and save it.

An invocation:

$ sh ./count-cmds.sh
2003 commands, and 15 entries that weren't marked executable

Ah great. So in fact, the script works fine in the latest version of SunOS/Solaris but fails in the older version that Chris is running. How old is it? It turns out that Solaris 8 came out a while back, in February 2004. The same year my book came out, and I tested the scripts on Solaris 9 prior to publication.

This leads to the dilemma: the script apparently doesn't work on a ten-year-old version of Solaris UNIX but works just fine on the latest release, Solaris 11. Should I care?

This is all tied to the legacy problem: how far back do you need to go to ensure that your software works? The previous OS release? Five years back? Ten? Longer? Legacy support has been in the news for Windows users, that's for sure, as Microsoft just axed support for the ancient Windows XP version of the flagship operating system. For the record, WinXP was released in October 2001. Fourteen years later, Microsoft is saying “guys, we've had a lot of major releases since then and can't support it forever”, and people are howling.

Apple seems to weather this sort of thing more gracefully. When the company moved from MacOS to Mac OS X, it included “Classic Mode” where old apps would mostly run, but the writing was on the wall from the beginning of the OS X era that Apple wasn't going to “do a Microsoft” and support the old OS for years and years.

And, this brings me back to Solaris 8 and Wicked Cool Shell Scripts. The long and short of it: if the script didn't work properly in Solaris 11, I'd be concerned and debug the problem, but because it fails in a ten-year-old version of the OS, I'm going to ignore the problem. If I could log in to a Solaris 8 system, I might debug it anyway just to understand what's going on, but is that a reason to slow down the revision of the book? I don't think so.

Legacy support—it's a big challenge for every software developer, and although Bash and the Linux command-line world hasn't changed that much in the past few years, it's still something to consider before you ship your own software (even if it's free software).

So what's your solution? Write to us, and let us know how your company deals with legacy Linux/UNIX issues!

Dave Taylor has been hacking shell scripts for more than 30 years. Really. He's the author of the popular Wicked Cool Shell Scripts and can be found on Twitter as @DaveTaylor and more generally at his tech site www.AskDaveTaylor.com.