2
foo()
{

  mapfile -t arr <<< "${1}"

  for i in "${!arr[@]}"
  do
    if [ -z "${arr[$i]}" ]
    then
      unset arr[$i]
    fi
  done

}

When I pass a variable with some content in it ( a big string basically ), I would like to :

  1. interpret the first word before the first whitespace as a key and everything after the first whitespace becomes the entry for that key in my associative array
  2. skip empty lines or lines with just a newline

example ( empty lines not included for compactness )

google https://www.google.com
yahoo https://www.yahoo.com
microsoft https://www.microsoft.com

the array should look like

[ google ] == https://www.google.com
[ yahoo ] == https://www.yahoo.com
[ microsoft ] == https://www.microsoft.com

I haven't found any good solution in the bash manual for the 2 points, the function foo that you see it's kind of an hack that creates an array and only after that it goes through the entire array and deletes the entries where the string is null .

So point 2 gets a solution, probably an inefficient one, but it works, but point 1 still doesn't have a good solution, and the alternative solution is to just create an array while iterating with read, as far as I know .

Do you know how to improve this ?

3
  • there is also a reason why I'm reluctant about using read, read usually shuffles the entries around and it doesn't replicate the original order, mapfile usually keeps things in the same order as the original string/file . Commented Oct 5, 2014 at 21:08
  • mapfile keeps everything in the original order because it doesn't create an associative array. read has nothing to do with the array you build, but presumably you are actually adding items one at a time to an associative array when you use it. Commented Oct 5, 2014 at 21:09
  • @chepner that's what I would like to have, a mapfile that creates associative arrays as described in my post, I don't have a final word about if this 2 points are doable or not with just the builtin commands from the bash . Commented Oct 5, 2014 at 21:11

1 Answer 1

6

mapfile doesn't build associative arrays (although if it could, the simplest solution to #2 would be to simply filter the input with, e.g., grep: mapfile -t arr < <(echo "$1" | grep -v "^$").

Falling back to an explicit loop using read, use the =~ operator to match and skip blank lines.

declare -A arr
while read key value; do
    if [[ $value =~ "^\s*$" ]]; then  # Or your favorite regex for skipping blank lines
        continue
    fi
    arr["$key"]="$value"
done <<< "$1"

You can also skip blank lines using grep even with the while loop:

declare -A arr
while read key value; do
   arr["$key"]="$value"
done < <(echo "$1" | grep '^\s*$')
Sign up to request clarification or add additional context in comments.

1 Comment

yes, this was my fallback solution, maybe with a custom IFS depending on the kind of input that I get, so this is not doable with the bash ?

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.