82

Thirteen Incorrect Ways and Two Awkward Ways to Use Arrays

 6 years ago
source link: http://www.oilshell.org/blog/2016/11/06.html
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.

Thirteen Incorrect Ways and Two Awkward Ways to Use Arrays

blog | oilshell.org

Thirteen Incorrect Ways and Two Awkward Ways to Use Arrays

2016-11-06

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:

  • Four incorrect ways of passing an array to a program
  • Nine incorrect ways of copying an array

We will also see that:

  • Correctly passing an array takes takes eight punctuation characters
  • Correctly copying an array takes ten punctuation characters

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.

RESULTS OF BAD WAYS TO PASS AN ARRAY

['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:

RESULTS OF BAD WAYS TO 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[*]}" )  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.


About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK