[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
Re: "${assoc[@]@k}" doesn't get expanded to separate words within compou
From: |
Greg Wooledge |
Subject: |
Re: "${assoc[@]@k}" doesn't get expanded to separate words within compound assignment syntax |
Date: |
Wed, 20 Mar 2024 07:49:15 -0400 |
On Wed, Mar 20, 2024 at 07:11:34AM -0400, Zachary Santer wrote:
> On Wed, Mar 20, 2024 at 12:29 AM Lawrence Velázquez <vq@larryv.me> wrote:
> > A couple of previous discussions:
> > - https://lists.gnu.org/archive/html/bug-bash/2020-12/msg00066.html
> > - https://lists.gnu.org/archive/html/bug-bash/2023-06/msg00128.html
>
> There I go, reporting a bug that isn't a bug again.
>
> One would think that enabling this behavior would be the entire
> purpose of the alternate ( key value ) syntax. If it doesn't do that,
> what benefit does it give over the standard ( [key]=value ) syntax?
> Maybe it;s easier to use eval with?
I believe the "X" in this X-Y problem is "I want to serialize an
associative array to a string, send the string to another bash script,
and de-serialize it back into an associative array there."
So, the first thing we observe is the behavior of the @k and @K expansions:
hobbit:~$ declare -A aa=('key 1' 'value 1' 'key 2' 'value 2')
hobbit:~$ declare -p aa
declare -A aa=(["key 2"]="value 2" ["key 1"]="value 1" )
hobbit:~$ printf '<%s> ' "${aa[@]@k}"; echo
<key 2> <value 2> <key 1> <value 1>
hobbit:~$ printf '<%s> ' "${aa[@]@K}"; echo
<"key 2" "value 2" "key 1" "value 1" >
Essentially, @k serializes the associative array to a list of alternating
keys/values, while @K serializes it to a string.
For the purposes of sending the serialization to another script, the
list is not suitable unless we NUL-terminate each element. We could
pursue that, but it's going to involve more work, I suspect.
Given the string serialization we get from @K, it makes sense to start
there, and try to determine whether it's eval-safe.
hobbit:~$ declare -A mess=('*' star '?' qmark $'\n' nl '$(date)' cmdsub '`id`'
backticks)
hobbit:~$ declare -p mess
declare -A mess=([$'\n']="nl" ["?"]="qmark" ["*"]="star" ["\$(date)"]="cmdsub"
["\`id\`"]="backticks" )
That's not comprehensive, but it's a start.
hobbit:~$ printf '<%s> ' "${mess[@]@K}"; echo
<$'\n' "nl" "?" "qmark" "*" "star" "\$(date)" "cmdsub" "\`id\`" "backticks" >
hobbit:~$ serial="${mess[@]@K}"
hobbit:~$ printf '<%s>\n' "$serial"
<$'\n' "nl" "?" "qmark" "*" "star" "\$(date)" "cmdsub" "\`id\`" "backticks" >
There's our serialization to a string. Now we'll try to de-serialize:
hobbit:~$ eval "declare -A copy=($serial)"
hobbit:~$ declare -p copy
declare -A copy=([$'\n']="nl" ["?"]="qmark" ["*"]="star" ["\$(date)"]="cmdsub"
["\`id\`"]="backticks" )
Looks OK. Let's verify another way:
hobbit:~$ for i in "${!copy[@]}"; do printf '<%s>: <%s>\n' "$i" "${copy[$i]}";
done
<
>: <nl>
<?>: <qmark>
<*>: <star>
<$(date)>: <cmdsub>
<`id`>: <backticks>
Unless someone else comes up with a key or value that breaks the eval,
this looks like the simplest way.
By comparison, the NUL-terminated @k list can't even be stored in a
variable, so you'd need to transmit it to the other script in some way
that's equivalent to using a temp file. Thus:
hobbit:~$ printf '%s\0' "${mess[@]@k}" > tmpfile
hobbit:~$ unset -v copy; declare -A copy; while IFS= read -rd '' key && IFS=
read -rd '' value; do copy[$key]=$value; done < tmpfile
hobbit:~$ declare -p copy
declare -A copy=([$'\n']="nl" ["?"]="qmark" ["*"]="star" ["\$(date)"]="cmdsub"
["\`id\`"]="backticks" )
I can't think of any way to restore an @k serialization other than a
IFS= read -rd '' loop. The only advantage I can see here is that it
doesn't use eval, and therefore is visibly safe. With the eval @K
solution, we're still left wondering whether the script is a ticking
time bomb.
- "${assoc[@]@k}" doesn't get expanded to separate words within compound assignment syntax, Zachary Santer, 2024/03/19
- Re: "${assoc[@]@k}" doesn't get expanded to separate words within compound assignment syntax, Lawrence Velázquez, 2024/03/20
- Re: "${assoc[@]@k}" doesn't get expanded to separate words within compound assignment syntax, Zachary Santer, 2024/03/20
- Re: "${assoc[@]@k}" doesn't get expanded to separate words within compound assignment syntax, Chet Ramey, 2024/03/22
- Re: "${assoc[@]@k}" doesn't get expanded to separate words within compound assignment syntax, Greg Wooledge, 2024/03/22
- Re: "${assoc[@]@k}" doesn't get expanded to separate words within compound assignment syntax, Lawrence Velázquez, 2024/03/22
- Re: "${assoc[@]@k}" doesn't get expanded to separate words within compound assignment syntax, Greg Wooledge, 2024/03/22