Thirteen Incorrect Ways and Two Awkward Ways to Use Arrays


The POSIX shell is a programming language with a single type: the string. It would have been better if this single type were an array of strings.

Why? Because the shell's purpose is to start processes, and every process takes an array of strings as input, regardless of the language it's written in.

For example, in Python:

$ python -c 'import sys; print sys.argv[1:]' foo bar
['foo', 'bar']

Word splitting in shell is a hack to work around the mismatch between the language's data structures and the problem domain. This causes many problems.

In this post we will see:

We will also see that:

Suppose you have an array like this:

a=('Track 01.mp3' 'Track 02.mp3')

and you want to pass these filenames with spaces to a program. What is the syntax for doing that?

In the interest of brevity, I'll show the output of the demonstration first, then a link to download the full program at the end.


['Track', '01.mp3']
['Track', '01.mp3', 'Track', '02.mp3']
['Track 01.mp3 Track 02.mp3']
['Track', '01.mp3', 'Track', '02.mp3']

GOOD WAY is "${a[@]}"  ->  ['Track 01.mp3', 'Track 02.mp3']

The first four ways mangle the filenames. They are:

$a  ${a[*]}  "${a[*]}"  ${a[@]}

The good way has an incredible 8 punctuation characters, in addition to the variable name: "${a[@]}".

It's even harder to correctly copy an array:


['Track 01.mp3']
['Track 01.mp3 Track 02.mp3']
['Track 01.mp3 Track 02.mp3']
['Track 01.mp3 Track 02.mp3']
['Track 01.mp3 Track 02.mp3']
['Track', '01.mp3']
['Track', '01.mp3', 'Track', '02.mp3']
['Track 01.mp3 Track 02.mp3']
['Track', '01.mp3', 'Track', '02.mp3']

GOOD WAY is b=( "${a[@]}" )  ->  ['Track 01.mp3', 'Track 02.mp3']

The nine wrong ways are:

b=${a[*]}  b="${a[*]}"  b=${a[@]}  b="${a[@]}"
b=( $a )
b=( ${a[*]} )  b=( "${a[*]}" )  b=( ${a[@]} )

The good way has 10 punctuation characters on the right-hand side, in addition to the variable name: ( "${a[@]}" ). I didn't learn this until I started working on implementing a shell. Typing it without using backspace has been a challenge!

Download the program

Oil Language

I haven't talked much about the oil language yet on this blog, but here's a glimpse. Arrays will be initialized with the more conventional [] syntax:

a = ['Track 01.mp3' 'Track 02.mp3']

To pass it, use the splice operator @:

my-prog -v @a

To copy it, splice it into a new array literal:

b = [ @a ]

(b = a isn't the syntax to copy an array, because I want to make copying explicit.)

So it takes 1 character rather than 8 to pass an array, and 3 characters rather than 10 to copy an array.

I have at least one more post about bad shell syntax planned, as well as a status update on the parser. After that, I hope to write more about the oil language.