1

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!

2
  • BTW, echo $arrayname only prints the first element, so echo $arrayname[1] is just printing the expansion of $arrayname, followed by printing the literal sequence [1]; it's not actually expressing to you that the first element "is the whole array" in any meaningful respect. Commented Jul 18, 2017 at 22:50
  • declare -p arrayname. Works for any other shell variable too. Commented Jul 19, 2017 at 16:09

1 Answer 1

6

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).
Sign up to request clarification or add additional context in comments.

2 Comments

You beat me to it :-)
Thanks for the answer! It was very helpful.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.