qodeninja
qodeninja

Reputation: 11296

How do you store a list of directories into an array in Bash (and then print them out)?

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!

Upvotes: 42

Views: 106357

Answers (4)

ocodo
ocodo

Reputation: 30319

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

Upvotes: 1

John Kugelman
John Kugelman

Reputation: 362187

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.

Upvotes: 31

Dennis Williamson
Dennis Williamson

Reputation: 360703

$ 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/!

Upvotes: 57

Jester
Jester

Reputation: 58822

#! /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]}"

Upvotes: 14

Related Questions