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

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.