Loading...
Working with Arrays in Linux Shell

Working with Arrays in Linux Shell

:heavy_exclamation_mark: This post is older than a year. Consider some information might not be accurate anymore. :heavy_exclamation_mark:

Used:   bash v3.2  zsh 5.3 

One necessity is dealing with Arrays as a data structure in any language or interpreter. The Linux Documentation Project has lots of documentation but lacks IMHO concise and straightforward examples. I created this example, as recently I have struggled myself how to operate on arrays. I spice it up with some ASCII art from asky.io (♥_♥).

The Example Program

I wrote this example on my MacBook Pro, which has two flavours of Linux Shell: Bash and Z shell.

There are minor differences in the feature set. The most important one:

  • zsh arrays start at index position 1
  • bash arrays start at index position 0

See a more detailed answer to that problem. Regardless pay attention, if you are using different shells.


Bash

Run with sh array-demo.sh:
detecting shell:
  using bash 3.2.57(1)-release

array: ¯\_(ツ)_/¯ This is a string array ᕙ(⇀‸↼‶)ᕗ

index 5: array

length: 7

last index: ᕙ(⇀‸↼‶)ᕗ

item: ¯\_(ツ)_/¯ has a length of 9

iterate over array
  ¯\_(ツ)_/¯
  This
  is
  a
  string
  array
  ᕙ(⇀‸↼‶)ᕗ

iterate with index
index: 0, value: ¯\_(ツ)_/¯
index: 1, value: This
index: 2, value: is
index: 3, value: a
index: 4, value: string
index: 5, value: array
index: 6, value: ᕙ(⇀‸↼‶)ᕗ

zsh

Run with zsh array-demo.sh:
detecting shell:
  using zsh 5.3

array: ¯\_(ツ)_/¯ This is a string array ᕙ(⇀‸↼‶)ᕗ

index 5: string

length: 7

last index: array

item:  has a length of 0

iterate over array
  ¯\_(ツ)_/¯
  This
  is
  a
  string
  array
  ᕙ(⇀‸↼‶)ᕗ
The major differences to bash:
  • at index 5 the value is string instead of array
  • the last value array is not correct, we expect ᕙ(⇀‸↼‶)ᕗ
  • the first item of index 0 is empty, the index in zsh starts with 1
Iteration with index does not work for the zsh. I don't miss that feature :smile:.

Resolve Issues

For the educational purpose, I use the variables INDEX_START and INDEX_OFFSET to accomplish identical results.


bash

Run bash array-demo-improved.sh
detecting shell:
  using bash 3.2.57(1)-release, index starts at 0

array: ¯\_(ツ)_/¯ This is a string array ᕙ(⇀‸↼‶)ᕗ

index 5: string

length: 7

last index: ᕙ(⇀‸↼‶)ᕗ

item: ¯\_(ツ)_/¯ has a length of 9

iterate over array
  ¯\_(ツ)_/¯
  This
  is
  a
  string
  array
  ᕙ(⇀‸↼‶)ᕗ

iterate with index
index: 0, value: ¯\_(ツ)_/¯
index: 1, value: This
index: 2, value: is
index: 3, value: a
index: 4, value: string
index: 5, value: array
index: 6, value: ᕙ(⇀‸↼‶)ᕗ

zsh

Run zsh array-demo-improved.sh
detecting shell:
  using zsh 5.3, index starts at 1

array: ¯\_(ツ)_/¯ This is a string array ᕙ(⇀‸↼‶)ᕗ

index 5: string

length: 7

last index: ᕙ(⇀‸↼‶)ᕗ

item: ¯\_(ツ)_/¯ has a length of 9

iterate over array
  ¯\_(ツ)_/¯
  This
  is
  a
  string
  array
  ᕙ(⇀‸↼‶)ᕗ

iterate with index
index: 1, value: ¯\_(ツ)_/¯
index: 2, value: This
index: 3, value: is
index: 4, value: a
index: 5, value: string
index: 6, value: array
index: 7, value: ᕙ(⇀‸↼‶)ᕗ

Compare with diff

To compare the two outputs, if your eye doesn’t see the difference :wink:

diff <(sh array-demo-improved.sh) <(zsh array-demo-improved.sh) 

Output:

2c2
<   using bash 3.2.57(1)-release, index starts at 0
---
>   using zsh 5.3, index starts at 1
24,30c24,30
< index: 0, value: ¯\_(ツ)_/¯
< index: 1, value: This
< index: 2, value: is
< index: 3, value: a
< index: 4, value: string
< index: 5, value: array
< index: 6, value: ᕙ(⇀‸↼‶)ᕗ
---
> index: 1, value: ¯\_(ツ)_/¯
> index: 2, value: This
> index: 3, value: is
> index: 4, value: a
> index: 5, value: string
> index: 6, value: array
> index: 7, value: ᕙ(⇀‸↼‶)ᕗ

Side by Side diff

diff -y <(sh array-demo-improved.sh) <(zsh array-demo-improved.sh) 

Output:

detecting shell:                                                detecting shell:
  using bash 3.2.57(1)-release, index starts at 0             |   using zsh 5.3, index starts at 1

array: ¯\_(ツ)_/¯ This is a string array ᕙ(⇀‸↼‶)ᕗ               array: ¯\_(ツ)_/¯ This is a string array ᕙ(⇀‸↼‶)ᕗ

index 5: string                                                 index 5: string

length: 7                                                       length: 7

last index: ᕙ(⇀‸↼‶)ᕗ                                            last index: ᕙ(⇀‸↼‶)ᕗ

item: ¯\_(ツ)_/¯ has a length of 9                              item: ¯\_(ツ)_/¯ has a length of 9

iterate over array                                              iterate over array
  ¯\_(ツ)_/¯                                                      ¯\_(ツ)_/¯
  This                                                            This
  is                                                              is
  a                                                               a
  string                                                          string
  array                                                           array
  ᕙ(⇀‸↼‶)ᕗ                                                        ᕙ(⇀‸↼‶)ᕗ

iterate with index                                              iterate with index
index: 0, value: ¯\_(ツ)_/¯                                   | index: 1, value: ¯\_(ツ)_/¯
index: 1, value: This                                         | index: 2, value: This
index: 2, value: is                                           | index: 3, value: is
index: 3, value: a                                            | index: 4, value: a
index: 4, value: string                                       | index: 5, value: string
index: 5, value: array                                        | index: 6, value: array
index: 6, value: ᕙ(⇀‸↼‶)ᕗ                                   | index: 7, value: ᕙ(⇀‸↼‶)ᕗ

For the popcorn geeks:

Updates

2019-02-02: Got the use case for taking a random element from an array.

players=(dragon stegosaurus daemon kitty koala)
# get player with random index number from beginning to the size of array (1-5)
starter=${players[$RANDOM % ${#players[@]}]}
echo $starter
Please remember the terms for blog comments.