3

Suppose I have the following list of files:

/aaa/bbb/file1.txt
/aaa/ccc/file2.txt
/aaa/bbb/file3.txt
/aaa/bbb/file4.txt
/aaa/ccc/file5.txt

And I'd like to have a set of all of the unique dirnames in an array. The resulting array would look something like this:

dirs=( "/aaa/bbb" "/aaa/ccc" )

I think I can do something like this, but it feels really verbose (pardon the syntax errors, i don't have a shell handy):

dirs=()
for f in filelist do
    dir=$(dirname $f)
    i=0
    while [$i -lt ${#dirs[@]} ]; do
        if [ dirs[$i] == $dir ]
            break
        fi
        i=$[i + 1]
    done
    if [ $i -eq ${dirs[@]} ]
        dirs+=($dir)
    fi
 done

1 Answer 1

2

Use associative arrays:

declare -A dirs

for f in "${filelist[@]}"; do
    dir=$(exec dirname "$f") ## Or dir=${f%/*}
    dirs[$dir]=$dir
done

printf '%s\n' "${dirs[@]}"

Or if input is from file:

readarray -t files < filelist
for f in "${files[@]}"; do
    dir=$(exec dirname "$f") ## Or dir=${f%/*}
    dirs[$dir]=$dir
done
  • Let's keep unnecessary forks on a subshell minimum with exec.
Sign up to request clarification or add additional context in comments.

15 Comments

You don't need to set the value to $dir, just the key: dirs[$dir]=1. You can then use "${!dirs[@]}" to get the list of keys, and if [ "${dirs[FOO]:-}" ] to test whether "FOO" is in the set.
@KeithThompson Yes I considered that. However I still chose to add the value anyway and use "${dirs[@]}".
You could apply that parameter expansion to the array itself in the second example: for file in "${files[@]%/*}"… (Also, you confuse f and file.)
@KeithThompson For less complexity. It's easier to process values over keys when you want to do other things like "${x[@]//something}".
@kojiro see this stackoverflow.com/a/22402242/632407 for the comparison of the basename/dirname and variable substituions. ;)
|

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.