Bourne Shell – Arrays in Unix Bourne Shell

arraybourne-shellshell

I am trying to use arrays in Bourne shell (/bin/sh). I found that the way to initialize array elements is:

arr=(1 2 3)

But it is encountering an error:

syntax error at line 8: `arr=' unexpected

Now the post where I found this syntax says it is for bash, but I could not find any separate syntax for Bourne shell. Does the syntax stand the same for /bin/sh as well?

Best Answer

/bin/sh is hardly ever a Bourne shell on any systems nowadays (even Solaris which was one of the last major system to include it has now switched to a POSIX sh for its /bin/sh in Solaris 11). /bin/sh was the Thompson shell in the early 70s. The Bourne shell replaced it in Unix V7 in 1979.

/bin/sh has been the Bourne shell for many years thereafter (or the Almquist shell, a free reimplementation on BSDs).

Nowadays, /bin/sh is more commonly an interpreter or another for the POSIX sh language which is itself based on a subset of the language of ksh88 (and a superset of the Bourne shell language with some incompatibilities).

The Bourne shell or the POSIX sh language specification don't support arrays. Or rather they have only one array: the positional parameters ($1, $2, $@, so one array per function as well).

ksh88 did have arrays which you set with set -A, but that didn't get specified in the POSIX sh as the syntax is awkward and not very usable.

Other shells with array/lists variables include: csh/tcsh, rc, es, bash (which mostly copied the ksh syntax the ksh93 way), yash, zsh, fish each with a different syntax (rc the shell of the once to-be successor of Unix, fish and zsh being the most consistent ones)...

In standard sh (also works in modern versions of the Bourne shell):

set '1st element' 2 3 # setting the array

set -- "$@" more # adding elements to the end of the array

shift 2 # removing elements (here 2) from the beginning of the array

printf '<%s>\n' "$@" # passing all the elements of the $@ array 
                     # as arguments to a command

for i do # looping over the  elements of the $@ array ($1, $2...)
  printf 'Looping over "%s"\n' "$i"
done

printf '%s\n' "$1" # accessing individual element of the array.
                   # up to the 9th only with the Bourne shell though
                   # (only the Bourne shell), and note that you need
                   # the braces (as in "${10}") past the 9th in other
                   # shells (except zsh, when not in sh emulation and
                   # most ash-based shells).

printf '%s\n' "$# elements in the array"

printf '%s\n' "$*" # join the elements of the array with the 
                   # first character (byte in some implementations)
                   # of $IFS (not in the Bourne shell where it's on
                   # space instead regardless of the value of $IFS)

(note that in the Bourne shell and ksh88, $IFS must contain the space character for "$@" to work properly (a bug), and in the Bourne shell, you can't access elements above $9 (${10} won't work, you can still do shift 1; echo "$9" or loop over them)).