The answer is going to be a bit long, but I've to address quite a few parts, so stick with me here.
Well, let's start off with the fact that your approach for iterating over grep output isn't quite right. The for i in $(); do ...done approach breaks with lines that contain leading spaces (due to word splitting), and generally isn't recommended(see this).
However, what typically is done is command | while IFS=<word separator> read -r variable; do...done (which as additional bonus is portable between Bourne-like shells). Also, I see that you're making use of cut -d : -f 1 to get first item out of colon-separated list in each line. We can make use of IFS=":" then to get rid of cut part. Your original command is thus transformed as so:
grep 'dook' /etc/trueuserowners | while IFS=":" read -r first_word everything_else
do
du -sh /home/$i
done | sort -nr
The first_word variable obviously will contain only the first field, and the unused everything_else will contain...everything else.
Note that I also quoted 'dook' part; although grep understands first item. Although grep understands first non-option item as PATTERN, it really is a good practice to protect pattern with single quotes, because if you use * or some other regex patterns that are used by the shell, that will unintentionally perform filename expansion by bash, and will attempt to read files in your current working directory. See this one for a detailed example.
Next, let's address arrays. We surely can add new item to arrays with the while loop I showed above, and += operator:
$ declare -a my_array
$ while IFS=":" read -r name null; do my_array+=("$name"); done < /etc/passwd
$ echo "${my_array[0]}"
root
This can be convenient if you want to process the items you're extracting later. However, considering the fact that you have pipe there, variables disappear once subshell in which while runs exits. See my old question about that.
What I'd recommend is processing everything in the while loop and use du -sb for precision in calculations. Thus, you could do:
# read what grep finds line by line and print total once there's no more lines from grep
grep 'dook' /etc/trueuserowners | while IFS=":" read -r first_word everything_else || { echo "$total"; break;}
do
user_usage=$( du -sb /home/"$first_word" | awk '{print $1}' )
# output the usage for current user
printf "%s\t/home/%s\n" "$user_usage" "$first_word"
total=$(($total+$user_usage))
done
Notice how I used || { echo "$total"; break;}. Once there's nothing to read from stdin ( which in this case comes from pipe ), read command returns exit status of 1, so when read returns 1 we know it's done reading and processing, and we can output the total usage we calculated.
As for outputting human-readable data, we could make use of numfmt or some other utilities. Something like numfmt --to=iec-i --suffix=B $user_usage would suffice.
Overall, this can be used as one-liner if we trim variable names to something short, but there's no particular advantage in having a one-liner. Just do things as correctly as possible and don't worry about code length.
Putting it all together, the complete solution should be:
grep 'dook' /etc/trueuserowners | while IFS=":" read -r username trash || { printf "%s\ttotal\n" $( numfmt --to=iec-i --suffix=B "$total"); break;}
do
# get usage in bytes
user_usage=$( du -sb /home/"$username" | awk '{print $1}' )
# get human-readable
usage_human_readable=$( numfmt --to=iec-i --suffix=B "$user_usage" )
# output the usage for current user
printf "%s\t/home/%s\n" "$usage_human_readable" "$username"
total=$(($total+$user_usage))
done