Timothy Chawaga
Timothy Chawaga

Reputation: 11

Populating an array from a directory list in bash

I've been trying to take the output of ls /Applications/ and put each line into an array, then do a for loop of the array.

#!/bin/bash
ls /Applications | grep Adobe > adobeapps
adobearray=( 'cat "adobeapps" ')
for i in "${adobearray[@]}"
do
    codeigottadowith $i
done
exit

It doesn't work, and I found that even when I try to just declare a simple array with:

declare -a adobearray=(item1 item2 item3); echo $adobearray[1];

The output is item1[1]. It takes the first element and makes that the whole array. Why is this wrong? What dumb thing am I doing? And is there a better way in bash to send the output of ls to an array?

Thanks for your help!

Upvotes: 1

Views: 917

Answers (1)

Charles Duffy
Charles Duffy

Reputation: 296039

What's the Right Way?

#!/bin/bash

# Cause a glob with no results to result in empty output, rather than to evaluate
# back to itself.
shopt -s nullglob

# Expand the glob /Applications/*Adobe* into an array
adobe_array=( /Applications/*Adobe* )

# Trim the prefix /Applications/ from each element of that array
adobe_array=( "${adobe_array[@]#/Applications/}" )

# Iterate over that array
for i in "${adobe_array[@]}"; do
  codeigottadowith "$i"
done

What was wrong earlier?

  • Parsing ls is inherently fault-prone. The command is designed for its output to be read by humans, not programs, and it doesn't support functionality (such as NUL-delimited output) necessary to resolve the related issues robustly.
  • adobearray=( 'cat "adobeapps" ') -- this puts the string cat "adobeapps" itself into the array as its only element; it doesn't actually run the cat command at all. If you did want to read from a file into an array, you'd be better off using mapfile instead (if targeting bash 4.0 or newer), though reading from a file generated with ls is inappropriate in the first place.
  • adobearray=( $(cat "adobeapps") ) -- This is closer, but also buggy. If an application name contains a space (and Adobe Acrobat and Adobe Photoshop all contain spaces), you would have Adobe as one entry and Acrobat as another. And if you had a program named * Adobe Foobar *, then the *s would be replaced with names of other files in the current directory where this code was invoked.
  • echo $adobearray[1] -- in order to index into an array, one needs to use braces to surround the parameter expansion; use echo "${adobearray[1]}" to emit the second item in your array (the first is index 0).

Upvotes: 6

Related Questions