1

I have an array with subdirs and files:

~$ array=(elem1/a elem1/b elem2/a elem2/b)

I need to select all files (with its subdir) inside subdir elem1.

I've tried with a for loop and case:

for element in "${array[@]}"; do
  case $element in
    elem1*)
    # action I need to perform on this element
      echo "This is $element"
    ;;
  esac
done

I'd like to get the list of elements I need using some glob, in a similar way as this (which substracts substrings from array elements):

~$ echo ${array[@]%/a}
elem1 elem1/b elem2 elem2/b

My main concern is that I shoudn't hardcode what strings I'm searching for, as I don't know its contents - in my final version of this script I'm getting them from another array.

1
  • 3
    There is no such conditional expansion operator. You have to fully expand the array, then decide in the body whether to work with the current value or continue to the next iteration. (Note; be sure to quote the array expansion: for element in "${array[@]}"; do.) Commented Dec 13, 2017 at 20:45

3 Answers 3

2

My answer prints every element of the array in a different line, then filters the ones you are interested (grep) and put them into a new array

newarray=( $(printf "%s\n" "${array[@]}" | grep ^elem/) )

The only problem would be if the elements of your array (subdirs and file namews) might contain EOL or blank chars.

Bonus

If your elements contain EOL or blank chars, you should use the NUL (\000) char and grep -zZ to handle it; but then you need more code to turn out those NUL-char strings into something which the bash can work with -- the bash stops reading when it finds a NUL char.

In this example I use awk, which has no problem to handle NUL chars, and makes unnecessary the use of grep:

 eval newarray=( $(printf "%s\000" "${A[@]}" |
                   awk 'BEGIN { FS="\000" }

                        /^elem\// {
                                    gsub("\042","\\\042")
                                    printf("[" NR-1 "]=\042%s\042 ",$0)
                                  }'
                   )
                )
Sign up to request clarification or add additional context in comments.

Comments

2

You can filter your array with a variable query (prefix below) and store the results in a new array (result):

#!/bin/bash
array=(elem1/a elem1/b elem2/a elem2/b)
prefix=elem1
result=()
for element in "${array[@]}"; do
    [[ $element == $prefix/* ]] && result+=("$element")
done

The result is:

$ declare -p result
declare -a result='([0]="elem1/a" [1]="elem1/b")'

Comments

1

here is one alternative

$ for e in "${array[@]}"; 
  do case "${e%%/*}" in
       elem1) echo "$e is in elem1" ;;
     esac
  done

elem1/a is in elem1
elem1/b is in elem1

2 Comments

I like this as you don't need to use grep! Can you explain that variable expansion? ${e%%/*}
it's not expansion, but string operation: cuts longest match of /* from back of variable e, that is returns the value until the first slash Here is a ref: tldp.org/LDP/abs/html/string-manipulation.html

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.