Adam
Adam

Reputation: 3138

Unseting a list of dynamic variables in Bash

How can I achieve the following with Bash:

x="search='something something' replace='something' subject=/path/path"

eval "$x"

echo $search
# prints something
# etc.

# (I am trying to do something here)
# So the following wouldn't print **something** anymore

echo $search

I basically want to unset the variables that were set using eval initially.

Upvotes: 1

Views: 180

Answers (2)

F. Hauri  - Give Up GitHub
F. Hauri - Give Up GitHub

Reputation: 70967

Preamble: Care using eval as eval is evil...
Whatever...

could do this very quickly:

unset ${x//=*([^ ])}

As pointed out by glenn jackman, this work only if there are no spaces in content of variables.

In this case, we could (very quickly too) prepare some intermediary variable (x without spaces):

xwos=${x//\"*([^\"])\"}        # This will drop `search="don't know"`
xwos=${xwos//\'*([^\'])\'}     # This will drop `search='blah blah'`
unset ${xwos//=*([^ ])}

In fine, adding this to your script will do the job:

xwos=${x//\"*([^\"])\"}; xwos=${xwos//\'*([^\'])\'}; unset ${xwos//=*([^ ])}

Explanation / showcase

Of course, you have to use extglob 's option, if not already set:

shopt -s extglob

Let's try:

x="search='something something' replace='something' subject=/path/path"

eval "$x"

echo $search 
something something

declare -p search replace subject
declare -- search="something something"
declare -- replace="something"
declare -- subject="/path/path"

shopt -s extglob
xwos=${x//\"*([^\"])\"}
printf 'X w/o double quoted spaces 1st:\n    "%s"\n' "$xwos"
X w/o double quoted spaces 1st:
    "search='something something' replace='something' subject=/path/path"

xwos=${xwos//\'*([^\'])\'}
printf 'X w/o single quoted spaces 2nd:\n    "%s"\n' "$xwos"
X w/o single quoted spaces 2nd:
    "search= replace= subject=/path/path"

printf 'String containing variables w/o values:\n    "%s"\n' "${xwos//=*([^ ])}"
String containing variables w/o values:
    "search replace subject"

unset ${xwos//=*([^ ])}

declare -p search replace subject
bash: declare: search: not found
bash: declare: replace: not found
bash: declare: subject: not found

Nota: If you don't need x anymore, you could redefine x instead of populating a new variable:

shopt -s extglob;x=${x//\"*([^\"])\"};x=${x//\'*([^\'])\'};unset ${x//=*([^ ])}

Demo

x="search='something something' replace='something' subject=/path/path"

eval "$x"

echo $search 
something something

shopt -s extglob;x=${x//\"*([^\"])\"};x=${x//\'*([^\'])\'};unset ${x//=*([^ ])}
echo $search
 

 

Upvotes: 3

anubhava
anubhava

Reputation: 785761

You can fork a subshell, do eval in the subshell and once you're done, exit the subshell:

# do this in a subshell
(
x="search='something' replace='something' subject=/path"
eval "$x"
echo "search=$search"
)

# now out of subshell
echo "search=$search"

Upvotes: 3

Related Questions