bug-bash
[Top][All Lists]
Advanced

[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: alex xmb sw ratchev
Subject: Re: "${assoc[@]@k}" doesn't get expanded to separate words within compound assignment syntax
Date: Wed, 20 Mar 2024 12:53:07 +0100

On Wed, Mar 20, 2024, 12:49 Greg Wooledge <greg@wooledge.org> wrote:

> 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."
>

as to that , simply declare -p and run that back

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.
>
>


reply via email to

[Prev in Thread] Current Thread [Next in Thread]