export
is the answer!
Interactive exercises by yourself
As shell is interactive, you could try near everything inline!
$ mkdir conf && printf 'MINIENTREGA_%s="%s"\n' FECHALIMITE 2011-03-31 FICHEROS \
"informe.txt programa.c" DESTINO ./destino/entrega-prac1 >conf/prac1
$ set -- prac1 # set "prac1" as positional argument "$1" see `help set`
$ while read -r line; do export $line; done <"conf/$1"
bash: export: `programa.c"': not a valid identifier
$ while read -r line; do LANG=C export "$line"; done <"conf/$1"
$ echo "$MINIENTREGA_FICHEROS"
"informe.txt programa.c"
Note the double quotes enclosing $line
on export
command!
source
alias .
$ set -- prac1
$ . "conf/$1"
$ echo "$MINIENTREGA_FICHEROS"
informe.txt programa.c
Ok! Then now what's about export
?
export
command tell shell to export his variables to environment... So you have to export script variables before use them is any subprocess (like ruby
, python
, perl
or even another shell
script.
Cleaning previous operations for further demos
$ declare +x MINIENTREGA_FECHALIMITE MINIENTREGA_FICHEROS MINIENTREGA_DESTINO
$ unset MINIENTREGA_FECHALIMITE MINIENTREGA_FICHEROS MINIENTREGA_DESTINO
So from an interactive shell, simpliest way to try this is to run another (sub) shell:
$ set -- prac1
$ . "conf/$1"
$ sh -c 'echo "$MINIENTREGA_FICHEROS"'
This just print an empty line, but if you export your variables:
$ export MINIENTREGA_FECHALIMITE MINIENTREGA_FICHEROS MINIENTREGA_DESTINO
$ sh -c 'echo "$MINIENTREGA_FICHEROS"'
informe.txt programa.c
Sample shell wrapper for exporting variables
Minimal wrapper, without security concern (care when sourcing script editable by other users!!).
#!/bin/sh
while IFS== read -r varname _;do
case $varname in
*[!A-Za-z0-9_]* | '' ) ;;
* ) export $varname ;;
esac
done <conf/$1
. conf/$1
busybox sh -c 'set | grep MINIENTREGA'
Run with prac1
as argument, should produce:
MINIENTREGA_DESTINO='./destino/entrega-prac1'
MINIENTREGA_FECHALIMITE='2011-03-31'
MINIENTREGA_FICHEROS='informe.txt programa.c'
In fine
This two operation can be done in any order indifferently. The only requirement is that both operations are done before you try to run any subprocess.
You could even do both operation together, by exporting in your config file, for sample:
export MINIENTREGA_FECHALIMITE="2011-03-31"
export MINIENTREGA_FICHEROS="informe.txt programa.c"
export MINIENTREGA_DESTINO="./destino/entrega-prac1"
You even could write this in one operation:
export MINIENTREGA_FICHEROS="informe.txt programa.c" \
MINIENTREGA_FECHALIMITE="2011-03-31" MINIENTREGA_DESTINO="./destino/entrega-prac1"
Some bashisms now
bash do offer a lot of tools for variable manipulations
Playing with variable names: nameref
#!/bin/bash
buildMiniEntragaVar() {
local -n _MiniEntragaVar="MINIENTREGA_$1"
export "MINIENTREGA_$1"
_MiniEntragaVar="$2"
}
buildMiniEntragaVar FECHALIMITE "2011-03-31"
buildMiniEntragaVar FICHEROS "informe.txt programa.c"
buildMiniEntragaVar DESTINO "./destino/entrega-prac1"
Then, using bash, you could show attribute and content of any variable by using declare -p
:
declare -p MINIENTREGA_FECHALIMITE MINIENTREGA_DESTINO MINIENTREGA_FICHEROS
declare -x MINIENTREGA_FECHALIMITE="2011-03-31"
declare -x MINIENTREGA_DESTINO="./destino/entrega-prac1"
declare -x MINIENTREGA_FICHEROS="informe.txt programa.c"
Expanding by variable name prefix matching:
This is a nice tool! From man page:
${!prefix*}
${!prefix@}
Names matching prefix. Expands to the names of variables whose
names begin with prefix, separated by the first character of the
IFS special variable. When @ is used and the expansion appears
within double quotes, each variable name expands to a separate
word.
In practice last previous sample, using declare -p
could be written:
declare -p ${!MINIENTREGA_*}
declare -x MINIENTREGA_DESTINO="./destino/entrega-prac1"
declare -x MINIENTREGA_FECHALIMITE="2011-03-31"
declare -x MINIENTREGA_FICHEROS="informe.txt programa.c"
Of course, this could be used to export
previously defined variables:
MINIENTREGA_FECHALIMITE="2011-03-31"
MINIENTREGA_FICHEROS="informe.txt programa.c"
MINIENTREGA_DESTINO="./destino/entrega-prac1"
export "${!MINIENTREGA_@}"
Unexporting a variable:
Unfortunely, there is no unexport
command. for this, you could use either flag -n
of export command or sign +
instead of -
for declare
command:
export -n MINIENTREGA_DESTINO
declare +x MINIENTREGA_FICHEROS
both commands will unset exportation flog of the variable.
Exporting array or associative array:
As bash array and associative array are kind of bashisms, they couldn't be exported at POSIX environment:
export -a myavar='(1 2)'
export -A myAvar='([foo]=1 [bar]=2)'
echo ${myavar[1]} ${myAvar[bar]}
2 2
declare -p "${!my@}"
declare -Ax myAvar=([foo]="1" [bar]="2" )
declare -ax myavar=([0]="1" [1]="2")
But
bash -c 'echo ${myavar[1]} ${myAvar[bar]}'
This just print an empty line!! While flag x
was present!
For this, a kind of workaround could be to use --rcfile with -i
flags:
bash --rcfile <(declare -p "${!my@}") --noediting -ic 'echo ${myavar[1]} ${myAvar[bar]}'
2 2
bash --rcfile <(declare -p "${!my@}") --noediting -i file.sh
Or if using interactive could cause issue, you could concatenate your script:
bash -c "$(declare -p "${!my@}");"'echo ${myavar[1]} ${myAvar[bar]}'
2 2
or
bash -c "$(declare -p "${!my@}");file.sh"
or even
bash -c "$(declare -p "${!my@}");. file.sh"
if file is not executable, like for sample:
bash -c "$(declare -p "${!my@}");. <(echo 'echo ${myavar[1]} ${myAvar[bar]}')"
2 2