• Uncategorized

About arrays : How-do-you-store-a-list-of-directories-into-an-array-in-Bash-and-then-print-them-out

Question Detail

I want to write a shell script to show a list of directories entered by a user and then for a user to select one of the directories with an index number based on how many directories there are

I’m thinking this is some kind of array operation, but im not sure how to do this in shell script

example:

> whichdir
There are 3 dirs in the current path
1 dir1
2 dir2
3 dir3
which dir do you want? 
> 3
you selected dir3!

Question Answer

$ ls -a
./ ../ .foo/ bar/ baz qux*
$ shopt -s dotglob
$ shopt -s nullglob
$ array=(*/)
$ for dir in "${array[@]}"; do echo "$dir"; done
.foo/
bar/
$ for dir in */; do echo "$dir"; done
.foo/
bar/
$ PS3="which dir do you want? "
$ echo "There are ${#array[@]} dirs in the current path"; \
select dir in "${array[@]}"; do echo "you selected ${dir}"'!'; break; done
There are 2 dirs in the current path
1) .foo/
2) bar/
which dir do you want? 2
you selected bar/!

Array syntax

Assuming you have the directories stored in an array:

dirs=(dir1 dir2 dir3)

You can get the length of the array thusly:

echo "There are ${#dirs[@]} dirs in the current path"

You can loop through it like so:

let i=1

for dir in "${dirs[@]}"; do
    echo "$((i++)) $dir"
done

And assuming you’ve gotten the user’s answer, you can index it as follows. Remember that arrays are 0-based so the 3rd entry is index 2.

answer=2

echo "you selected ${dirs[$answer]}!"

Find

How do you get the file names into an array, anyways? It’s a bit tricky. If you have find that might be the best way:

readarray -t dirs < <(find . -maxdepth 1 -type d -printf '%P\n')

The -maxdepth 1 stops find from looking through subdirectories, -type d tells it to find directories and skip files, and -printf '%P\n' tells it to print the directory names without the leading ./ it normally likes to print.

#! /bin/bash

declare -a dirs
i=1
for d in */
do
    dirs[i++]="${d%/}"
done
echo "There are ${#dirs[@]} dirs in the current path"
for((i=1;i<=${#dirs[@]};i++))
do
    echo $i "${dirs[i]}"
done
echo "which dir do you want?"
echo -n "> "
read i
echo "you selected ${dirs[$i]}"

Update: my answer is wrong

Leaving it here to address a common misunderstanding, below the line is erroneous.


To put the directories in an array you can do…

array=( $( ls -1p | grep / | sed 's/^\(.*\)/"\1"/') )

This will capture the dir names, including those with spaces.


Extracting from comments:

literal quotes don’t have any effect on string-splitting, so array=( echo ‘”hello world” “goodbye world”‘ ) is an array with four elements, not two

@Charles Duffy

Charles also supplied the following link Bash FAQ #50 which is an extended discussion on this issue.

I should also draw attention to the link posted by @Dennis Williamson – why I shouldn’t have used ls

You may also like...

Leave a Reply

Your email address will not be published.

This site uses Akismet to reduce spam. Learn how your comment data is processed.