Bash: Set Array Env Variable and De-Referencing It from Any Shell Script Fails

bash: set array env variable and de-referencing it from any shell script fails

Read the fine manual, "bugs" section.

Array variables may not (yet) be exported.

Though, I don't know that many consider this an actual bug. Other shells that support ksh-style arrays don't allow exporting them either.

You may pass around array definitions rather easily, through parameters or variables or the environment. It isn't usually very useful though.

function f {
unset -v "$2"
typeset "$2"
eval "${!1}"
typeset -p "$2"
}

typeset -a a=(a b c)
myArr=$(typeset -p a) f myArr a

How to set value for bash array using setenv

Arrays are handled by bash, they don't exist as environment variables. Environment variables are stored in kernel per process as VARNAME=value, you can check this:

$ cat /proc/$$/environ | tr '\0' '\n'

But you can use array in the form of string with delimiter (coma or tab sign or whatever):

info=192.168.1.1:,AA-AA-AA-BB-BB-BB:

and handle this string in appropriate way

Also you should be careful with its names. First of all there is specific requirements on how the name should be composed:

Environment variable names used by the utilities in the Shell and
Utilities volume of IEEE Std 1003.1-2001 consist solely of uppercase
letters, digits, and the '_' (underscore) from the characters defined
in Portable Character Set and do not begin with a digit. Other
characters may be permitted by an implementation; applications shall
tolerate the presence of such names.

The second thing to note is that you risk to modify some variable some other component of program is relying on.

Can someone explain the strange result of set in Bash Shell, please?

The set command lists not only shell variables but also shell functions. Use env if you want only variables.

How to substitute shell variables in complex text files

Looking, it turns out on my system there is an envsubst command which is part of the gettext-base package.

So, this makes it easy:

envsubst < "source.txt" > "destination.txt"

Note if you want to use the same file for both, you'll have to use something like moreutil's sponge, as suggested by Johnny Utahh: envsubst < "source.txt" | sponge "source.txt". (Because the shell redirect will otherwise empty the file before its read.)

Array of arrays in bash

Bash has no support for multidimensional arrays. Try

array=(a b c d)
echo ${array[1]}
echo ${array[1][3]}
echo ${array[1]exit}

For tricks how to simulate them, see Advanced Bash Scripting Guide.

bash: set array env variable and de-referencing it from any shell script fails

Read the fine manual, "bugs" section.

Array variables may not (yet) be exported.

Though, I don't know that many consider this an actual bug. Other shells that support ksh-style arrays don't allow exporting them either.

You may pass around array definitions rather easily, through parameters or variables or the environment. It isn't usually very useful though.

function f {
unset -v "$2"
typeset "$2"
eval "${!1}"
typeset -p "$2"
}

typeset -a a=(a b c)
myArr=$(typeset -p a) f myArr a

When do we need curly braces around shell variables?

In this particular example, it makes no difference. However, the {} in ${} are useful if you want to expand the variable foo in the string

"${foo}bar"

since "$foobar" would instead expand the variable identified by foobar.

Curly braces are also unconditionally required when:

  • expanding array elements, as in ${array[42]}
  • using parameter expansion operations, as in ${filename%.*} (remove extension)
  • expanding positional parameters beyond 9: "$8 $9 ${10} ${11}"

Doing this everywhere, instead of just in potentially ambiguous cases, can be considered good programming practice. This is both for consistency and to avoid surprises like $foo_$bar.jpg, where it's not visually obvious that the underscore becomes part of the variable name.

Expansion of variables inside single quotes in a command in Bash

Inside single quotes everything is preserved literally, without exception.

That means you have to close the quotes, insert something, and then re-enter again.

'before'"$variable"'after'
'before'"'"'after'
'before'\''after'

Word concatenation is simply done by juxtaposition. As you can verify, each of the above lines is a single word to the shell. Quotes (single or double quotes, depending on the situation) don't isolate words. They are only used to disable interpretation of various special characters, like whitespace, $, ;... For a good tutorial on quoting see Mark Reed's answer. Also relevant: Which characters need to be escaped in bash?

Do not concatenate strings interpreted by a shell

You should absolutely avoid building shell commands by concatenating variables. This is a bad idea similar to concatenation of SQL fragments (SQL injection!).

Usually it is possible to have placeholders in the command, and to supply the command together with variables so that the callee can receive them from the invocation arguments list.

For example, the following is very unsafe. DON'T DO THIS

script="echo \"Argument 1 is: $myvar\""
/bin/sh -c "$script"

If the contents of $myvar is untrusted, here is an exploit:

myvar='foo"; echo "you were hacked'

Instead of the above invocation, use positional arguments. The following invocation is better -- it's not exploitable:

script='echo "arg 1 is: $1"'
/bin/sh -c "$script" -- "$myvar"

Note the use of single ticks in the assignment to script, which means that it's taken literally, without variable expansion or any other form of interpretation.

Unable to find match with yq in for loop

Call yq with the loop variable set in the environment, and use env within yq to read environment variables. See also the section Env Variable Operators in the manual.

ar=( "abc" "test" "xyz" )
for i in "${ar[@]}" # Prints nothing
do
i="$i" yq e 'keys | .[] | select(. == env(i))' .github/teams.yml
done

Another way could be to import the (preformatted) array from the environment and just make the array subtractions within yq (saving you the looping and calling yq multiple times):

ar='["abc","test","xyz"]' yq e 'env(ar) - (env(ar) - keys) | .[]' .github/teams.yml 


Related Topics



Leave a reply



Submit