Bash – source without polluting own namespace [get variables from other scripts in a safe manner]

bashshell-script

I'd like to assign the contents of variables of another bash script to variables in the calling script.

Specifically, I source this file: https://projects.archlinux.org/svntogit/packages.git/plain/trunk/PKGBUILD?h=packages/firefox (and other alike files).

The file contains variables named depends, makedepends, etc.

So in my script I have multiple statements like these:

depends="$(source "/path/to/file" ; printf '%s' "${depends[@]}")"
makedepends="$(source "/path/to/file" ; printf '%s' "${makedepends[@]}")"
...

So basically, each statement starts it's own subshell which sources the file and prints the contents of just ONE variable to a variable in the parent shell.

Is there another way which involves to start just a SINGLE subshell, source the file and get the contents of specified variables of the file assigned to specified variables in the calling shell without polluting the environment of the calling shell?

————————————————————————

Since Mark Mann pointed out the dangers of source-ing foreign scripts, I ended up with another solution. Instead of using source to get variables of another script, one can use a multi line grep with a perl regex to grep all needed variables from the file (varName=(…),varName2="…",varname3='…',varName4=…) and eval the result:

$ grepvars='(license)|(depends)|(makedepends)|(url)|(pkgdesc)|(pkgver)'
$
$ eval $(grep -Pzo "^(${grepvars})=\([^\)\(\`]*\)|^(${grepvars})=\"[^\"\(\`]*\"|^(${grepvars})='\''[^'\'']*'\''|^(${grepvars})=[^\s;\(\`]*" /tmp/above_mentioned_file)
$ echo $url
https://www.mozilla.org/firefox/
$
$ echo ${depends[@]}
gtk3 gtk2 mozilla-common libxt startup-notification mime-types dbus-glib alsa-lib ffmpeg2.8 desktop-file-utils hicolor-icon-theme libvpx icu libevent nss hunspell sqlite ttf-font

Best Answer

Use eval.

If you have your source (in /tmp/other.sh):

a=1
b=2
c=3

And you want only a portion, you can use eval to get just those items (here in /tmp/main.sh):

eval $(source /tmp/other.sh;
       echo a="$a";
       echo b="$b";)

echo a is $a "(expect 1)"
echo b is $b "(expect 2)"
echo c is $c "(expect nothing)"

And running it:

$ bash /tmp/main.sh
a is 1 (expect 1)
b is 2 (expect 2)
c is (expect nothing)

WARNING: Performing an eval or source on an untrusted script is very dangerous. You're executing a shell script, and that script can perform anything you could do yourself. WARNING

Related Question