help-bash
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: looping over variables & exporting them at the same time ?


From: Paxsali
Subject: Re: looping over variables & exporting them at the same time ?
Date: Sat, 27 Jan 2024 20:06:41 +0100

Have you tried "name reference" variables?

help declare # see -n option

Example:

A='hello'
B='world'

# show the properties and content of the variables (BEFORE):
echo "${A@A}"
echo "${B@A}"

# output (BEFORE):
# A='hello'
# B='world'

declare -n var
for var in A B; do
    var="$(printf '%s' "${var}" | tr 'o' '!')"
    export var
done

# show the properties and content of the variables (AFTER):
echo "${A@A}"
echo "${B@A}"

# output:
# declare -x A='hell!'
# declare -x B='w!rld'

the "declare -x" means the variable is exported.
the content has changed according to the manipulation (in my example "tr"
instead of "sed", but you can do whatever).

is that what you were looking for?

Greg Wooledge <greg@wooledge.org> schrieb am Sa., 27. Jan. 2024, 16:12:

> On Sat, Jan 27, 2024 at 08:22:17AM -0500, heavy.gear5130@fastmail.com
> wrote:
> > I have two variables defined in my env.
> >
> >       echo $A; echo $B
> >
> >               this is a test xtest of A str
> >               this is a test xtest of B str
>
> The indentation is confusing here.  Is there a bunch of leading whitespace
> in each variable's contents?  Or did you simply indent the output?
>
> Also, you said "in my env".  Are these really environment variables, or
> are they just regular variables?  (It might not matter.)
>
> > I want to loop over the varable names, A & B, editing the strings and
> exporting the values.
>
> This is quite unclear.  You want to loop over the *names*?  What does
> that mean?  What does "edit" mean?  What "values" are you talking about?
>
> > One at a time, without a loop, I would do
> >
> >       export A=$( echo "$A" | sed -e 's| xtest | |g' )
> >       export B=$( echo "$B" | sed -e 's| xtest | |g' )
>
> Are the contents actually *lists*?  Lists of words?  With whitespace
> separating them?
>
> And you'd like to *remove* one word from a given list, resulting in a
> new, smaller list?
>
> (Also by the way, what you've got here doesn't work if the word to be
> removed is at the beginning or end of the string.)
>
> > So after,
> >
> >       echo $A; echo $B
> >
> >               this is a test of A str
> >               this is a test of B str
>
> It seems so.  Although you're doing it in the most *primitive* way
> imaginable.
>
> >       for vars in A B
> >       do
> >         export $vars=$( echo $vars | sed -e 's| xtest | |g' )
> >       done
>
> > I guess I need some sort of indirection or escaping ?
>
> Yikes.  This is a mess.
>
> The *first* thing I'm going to say is that you are working in the wrong
> language.  Bash doesn't have the type of data structures you're trying
> to mock up here.  What you actually want is a *dictionary of lists of
> strings*.
>
> In most other languages, you could just specify that.  "I want a
> dictionary, indexed by strings A B etc., whose values are lists
> of words."  Then you'd just write code to manipulate those lists.
>
> Bash has dictionaries (associative arrays), and it has lists, kind of
> (indexed arrays).  But what it does *not* have are dictionaries *of*
> lists.  It only has dictionaries of strings.
>
> So to do this in bash, you'd need to mock up at least one layer.  In
> this case, you'd most likely store your list in a string variable,
> exactly as you're doing now.  Then you could have a dictionary of
> strings, and you could de-serialize and re-serialize each string back
> and forth between string form and list form as needed.  (Hopefully
> without calling *sed* of all things.)
>
> But then you've got this other "oh by the way" piece in your puzzle:
> you want each dictionary index value to be a *valid environment
> variable name*, and you want to *export* each piece of the dictionary
> to the environment.  For some completely unknown reason.  That's
> the part that's going to be especially ugly.
>
> And you never really specified where these lists come from.  It's
> implied that they arrive in the form of environment variables.  (This
> is horrifying, by the way.  It reminds me of sysadmin crap that you'd
> see in stuff that was written as if we were still in the 1980s.)
>
> So, let's assume the following:
>
>  1) Your inputs are environment variables.
>  2) Your outputs are also environment variables.
>  3) The output variable name is the same as the input variable name.
>  4) You KNOW IN ADVANCE the names of each environment variable that
>     you will process.  You do NOT need to scan through the entire
>     environment looking for matching patterns in the variable names.
>  5) Each variable contains a list of words delimited by spaces.
>  6) No word contains spaces internally.  There is no quoting needed.
>  7) The processing to be performed is the removal of ONE word from EACH
>     variable's contents, if found.  All instances should be removed.
>  8) You are working in bash, not sh.
>  9) The input variable contents do not contain newline characters.
>
> Given the primitive nature of the task, we'll use primitive techniques.
> No dictionary is needed, because we will only process one variable at
> a time.
>
> Here's a script based on what it appears you were trying to do:
>
> #!/bin/bash
> # This should work in bash 3.1 or newer.
>
> vars=(A B)
> remove=xtest
>
> for v in "${vars[@]}"; do
>     # Skip missing variables.
>     if [[ ! ${!v+defined} ]]; then
>         printf 1>&2 '%s is not defined. Skipping.\n' "$v"
>         continue
>     fi
>
>     # De-serialize the string into a list.
>     # This part will fail if the contents may contain newlines.
>     IFS=' ' read -ra list <<< "${!v}"
>
>     # Scan the list for the word to be removed, generating a new list.
>     outlist=()
>     for word in "${list[@]}"; do
>         [[ $word != $remove ]] && outlist+=("$word")
>     done
>
>     # The previous step could also have been done "in-place" by
>     # iterating the list by index, and unsetting the array values
>     # that need to be removed.  Generating a second list is simpler.
>     # Feel free to use the unset method if you prefer that.
>
>     # Re-serialize the output list back to a string.
>     # This uses the value of IFS, which we're assuming is default.
>     # If your script changes IFS, then this line will need to change.
>     out="${outlist[*]}"
>
>     # Re-export it under its original name.
>     # Post-eval, we will issue this command: export var="$out"
>     # This is safe ONLY because we control the contents of v.
>     # If v could be found by a dynamic scan of the incoming environment
>     # variables, we would need an additional sanity check on the name.
>     eval "export $v=\"\$out\""
> done
>
>


reply via email to

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