Bash Arrays

 in

If you're used to a "standard" *NIX shell you may not be familiar with bash's array feature. Although not as powerful as similar constructs in the P languages (Perl, Python, and PHP) and others, they are often quite useful.

Bash arrays have numbered indexes only, but they are sparse, ie you don't have to define all the indexes. An entire array can be assigned by enclosing the array items in parenthesis:

  arr=(Hello World)
Individual items can be assigned with the familiar array syntax (unless you're used to Basic or Fortran):
  arr[0]=Hello
  arr[1]=World
But it gets a bit ugly when you want to refer to an array item:
  echo ${arr[0]} ${arr[1]}
To quote from the man page:
The braces are required to avoid conflicts with pathname expansion.

In addition the following funky constructs are available:

  ${arr[*]}         # All of the items in the array
  ${!arr[*]}        # All of the indexes in the array
  ${#arr[*]}        # Number of items in the array
  ${#arr[0]}        # Length of item zero
The ${!arr[*]} is a relatively new addition to bash, it was not part of the original array implementation.

The following example shows some simple array usage (note the "[index]=value" assignment to assign a specific index):

#!/bin/bash

array=(one two three four [5]=five)

echo "Array size: ${#array[*]}"

echo "Array items:"
for item in ${array[*]}
do
    printf "   %s\n" $item
done

echo "Array indexes:"
for index in ${!array[*]}
do
    printf "   %d\n" $index
done

echo "Array items and indexes:"
for index in ${!array[*]}
do
    printf "%4d: %s\n" $index ${array[$index]}
done
Running it produces the following output:
Array size: 5
Array items:
   one
   two
   three
   four
   five
Array indexes:
   0
   1
   2
   3
   5
Array items and indexes:
   0: one
   1: two
   2: three
   3: four
   5: five

Note that the "@" sign can be used instead of the "*" in constructs such as ${arr[*]}, the result is the same except when expanding to the items of the array within a quoted string. In this case the behavior is the same as when expanding "$*" and "$@" within quoted strings: "${arr[*]}" returns all the items as a single word, whereas "${arr[@]}" returns each item as a separate word.

The following example shows how unquoted, quoted "*", and quoted "@" affect the expansion (particularly important when the array items themselves contain spaces):

#!/bin/bash

array=("first item" "second item" "third" "item")

echo "Number of items in original array: ${#array[*]}"
for ix in ${!array[*]}
do
    printf "   %s\n" "${array[$ix]}"
done
echo

arr=(${array[*]})
echo "After unquoted expansion: ${#arr[*]}"
for ix in ${!arr[*]}
do
    printf "   %s\n" "${arr[$ix]}"
done
echo

arr=("${array[*]}")
echo "After * quoted expansion: ${#arr[*]}"
for ix in ${!arr[*]}
do
    printf "   %s\n" "${arr[$ix]}"
done
echo

arr=("${array[@]}")
echo "After @ quoted expansion: ${#arr[*]}"
for ix in ${!arr[*]}
do
    printf "   %s\n" "${arr[$ix]}"
done
When run it outputs:
Number of items in original array: 4
   first item
   second item
   third
   item

After unquoted expansion: 6
   first
   item
   second
   item
   third
   item

After * quoted expansion: 1
   first item second item third item

After @ quoted expansion: 4
   first item
   second item
   third
   item

______________________

Mitch Frazier is an Associate Editor for Linux Journal.

Comments

Comment viewing options

Select your preferred way to display the comments and click "Save settings" to activate your changes.

Script fails?

EvilDave's picture

The example script fails on my Solaris 9 server using GNU Bash-2.05. Of course you do mention that the ${!array[*]} is fairly new so it appears not to be in my version of bash. Posting what version you are using would be helpful.

Here's the output I got.

#
Array size: 5
Array items:
one
two
three
four
five
Array indexes:
Array items and indexes:

Thanks!

SQLITE

Amr El-Sharnoby's picture

Hello,
Thanks for this article, Using bash arrays is MUST to avoid using tmp files and unnessary loops in some cases ...
But for large amount of data, I'd highly recommend using sqlite databases which is much faster and allows better functions ...

Think big

Mitch Frazier's picture

When I have a lot of data to store I use a Sun Fire X4500 server with 48 Terabytes of attached storage. What I like most about this is that it's a one to one swap for using bash.

Geez...

Mitch Frazier is an Associate Editor for Linux Journal.

Array in bash is really

Jadu Saikia's picture

Array in bash is really helpful. Here is how we can join two arrays in bash

http://unstableme.blogspot.com/2008/12/join-two-arrays-in-bash-script.html

what about speed

Anonymous's picture

hmm, I've tried once to use bash arrays in a simple script, which looked for specified strings in all cvs revisions of a file. But it seemed to work rather slowly.

Trolls

EvilDave's picture

So he tried it "ONCE" and decided it was slow? Hmmmm...

Pretty weak

Mitch Frazier's picture

Since you don't really give us any details to support your assertion: no source for your script and no details of other bash based implementations that proved faster, I have to assume that the slowness was related to CVS, or to searching, or possibly to bash in general, but I doubt it had anything do with bash arrays.

Mitch Frazier is an Associate Editor for Linux Journal.

speed

Kevin Cantu's picture

That's clearly just a troll. Bash is useful and the author doesn't need to justify its relevance. :D

White Paper
Linux Management with Red Hat Satellite: Measuring Business Impact and ROI

Linux has become a key foundation for supporting today's rapidly growing IT environments. Linux is being used to deploy business applications and databases, trading on its reputation as a low-cost operating environment. For many IT organizations, Linux is a mainstay for deploying Web servers and has evolved from handling basic file, print, and utility workloads to running mission-critical applications and databases, physically, virtually, and in the cloud. As Linux grows in importance in terms of value to the business, managing Linux environments to high standards of service quality — availability, security, and performance — becomes an essential requirement for business success.

Learn More

Sponsored by Red Hat

White Paper
Private PaaS for the Agile Enterprise

If you already use virtualized infrastructure, you are well on your way to leveraging the power of the cloud. Virtualization offers the promise of limitless resources, but how do you manage that scalability when your DevOps team doesn’t scale? In today’s hypercompetitive markets, fast results can make a difference between leading the pack vs. obsolescence. Organizations need more benefits from cloud computing than just raw resources. They need agility, flexibility, convenience, ROI, and control.

Stackato private Platform-as-a-Service technology from ActiveState extends your private cloud infrastructure by creating a private PaaS to provide on-demand availability, flexibility, control, and ultimately, faster time-to-market for your enterprise.

Learn More

Sponsored by ActiveState