6

Imagine I created an array like this:

IFS="|" read -ra ARR <<< "zero|one|||four"

now

echo ${#ARR[@]}
> 5
echo "${ARR[@]}"
> zero one   four
echo "${ARR[0]}"
> zero
echo "${ARR[2]}"
> # Nothing, because it is empty

The question is how can I replace the empty elements with another string?

I have tried

${ARR[@]///other}
${ARR[@]//""/other}

none of them worked.

I want this as output:

zero one other other four
9
  • Obviously I can write a loop, but a more concise solution would be nice Commented Jan 27, 2017 at 12:02
  • "${arr[2]:-other}" works, but printf "%s\n" "${arr[@]:-other}" does not, which makes sense but it is a pity because the trick on Shell parameter expansion on arrays is useful. I guess a loop will be necessary Commented Jan 27, 2017 at 12:13
  • @sat, I was just giving a way the array could be created. There are obviously many other ways to create the array. Commented Jan 27, 2017 at 12:15
  • @fedorqui, yes I thought too, but it seems parameter expansion doesn't work this way. Commented Jan 27, 2017 at 12:19
  • 1
    @fedorqui accepted Commented Feb 22, 2017 at 12:12

3 Answers 3

4

To have the shell expansion behave, you need to loop through its elements and perform the replacement on each one of them:

$ IFS="|" read -ra ARR <<< "zero|one|||four"
$ for i in "${ARR[@]}"; do echo "${i:-other}"; done
zero
one
other
other
four

Where:

${parameter:-word}

If parameter is unset or null, the expansion of word is substituted. Otherwise, the value of parameter is substituted.

To store them in a new array, just do so by appending with +=( element ):

$ new=()
$ for i in "${ARR[@]}"; do new+=("${i:-other}"); done
$ printf "%s\n" "${new[@]}"
zero
one
other
other
four
Sign up to request clarification or add additional context in comments.

Comments

4

If you want to replace all empty values (actually modifying the list), you could do this :

for i in "${!ARR[@]}" ; do ARR[$i]="${ARR[$i]:-other}"; done

Which looks like this when indented (more readable I would say) :

for i in "${!ARR[@]}"
do
  ARR[$i]="${ARR[$i]:-other}"
done

11 Comments

I tried creating an array with three elements (ARR[12]="", ARR[123]=foo, ARR[3456]=bar), then performed the command I suggested, and it contained the expected result (other foo bar), at the same positions as before. Would you care to elaborate in which conditions you think it would not work?
I tested it with an associative array too (even though I do not think it was the OP intended usage), and it seems to work in my shell.
Agreed, mis-interpreted with a similar syntax I tried locally, would gladly do +1, but OP insisted on a answer without loops
Unless there actually is a loop-free solution someone comes up with (that does not turn to be loop-free at the expense of being clunky or inefficient just for the sake of being loop-free), the best solution probably will be some kind of simple loop like this.
I gave this an up vote, even though it uses a loop, as currently no one has come up with a loop free version, and this is succinct solution.
|
4
# Temporary array initialization       
NEW=()

# Loop over the array, add only non-empty values to the new array
for i in "${ARR[@]}"; do

   # Skip null items
   if [ -z "$i" ]; then
     continue
   fi

   # Add the rest of the elements to an array
   NEW+=("${i}")

done

# Reinitialize your array
ARR=(${NEW[@]})

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.