3

How do I get a variable's value from one script and import it in another script? But the catch is that the script where I am going to get the variable's value has also some commands that I don't want to run:

Let's say this is script1.sh:

variable="Hello"
#some command here e.g. yum check-update

And in script2.sh:

echo $var

I've found an approach where one uses the EXPORT command and puts ./script1.sh inside the script2.sh but it runs the other commands.

So, how can I get the variable's value without running the commands inside it? I hope this question is clear. Thanks in advance!

3 Answers3

6

To summarize, you want to retrieve a value out of script1.sh without running all the commands in script1.sh. I will assume that script1.sh is not under your control, possibly because it is vendor-provided, or managed by an obstinate colleague, or similar such issue, which makes it so that script1.sh has to be used as is.

I will present two approaches. The first is good for getting specific variables out of script1.sh, one at time:

var=$(awk -F'"' '/^variable=/ {print $2}' script1.sh )
echo $var

This uses awk to read (not execute, just read) script1.sh. awk looks for the line that begins with variable= and then writes what appears after the double-quote mark on that line. The output from awk is capture into variable var.

In more detail:

  • The statement is of the form var=$(...). This means that whatever is in the parentheses is run as a bash command and its standard output is assigned to the variable var.

  • Inside the parentheses, we have the awk command: awk -F'"' '/^variable=/ {print $2}' script1.sh. Let us consider it in parts.

  • awk breaks lines (records) into fields. -F'"' tells awk to use double-quote as a field separator.

  • /^variable=/ tells awk to restrict operation to lines that begin with variable=. Thus, all the miscellaneous commands in script1.sh will be ignored.

  • {print $2} tells awk to print the second field. This means whatever is between the first and second occurence of a double-quote character.

  • The last argument to awk tells it what file to read: script1.sh.

The above approach is good for handling one variable at a time and allows you to rename the variable if you like.

How to handle many variables

If you want to source all the variables assigned in script1.sh, consider:

source <(grep -E '^\w+=' script1.sh)

This uses grep to extract all lines from script1.sh that look like variable assignments. These lines are then run in the current shell, assigning the variables.

If you use this approach first check to make sure that you want all the variables and that there aren't any that will interfere with what you are doing. If there are such, we can exclude them with a second grep command.

Considering the pieces in turn:

  • source file tells the shell to execute the file in the current shell.

  • <(...) is called process substitution. It allows us to use the output of a command in place of a file name.

  • The command grep -E '^\w+=' script1.sh extracts all lines that seem like variable assignments. If you run this command by itself on the command line, you should see something like:

    variable="Hello"
    var2="Value2"
    

    and so on. You should do this first and inspect the output to make sure that these are the lines that you want to execute.

John1024
  • 74,655
  • This approach works. Thanks, @John1024! Do you have another approach but with lesser characters? I'm going to use like, 200+ variables. – Miguel Roque Jun 09 '14 at 02:45
  • @MiguelRoque OK. Answer updated. – John1024 Jun 09 '14 at 02:56
  • source <(grep -E '\w+=' script1.sh) works! Thanks again, @John1024! – Miguel Roque Jun 09 '14 at 05:13
  • 1
    Note that because you don't anchor it, grep -E '\w+=' is equivalent to grep '\w=' and would match on configure --prefix=/opt/foo or echo foo=bar for instance. You may want to be a bit more restrictive, like in grep -E '^[[:blank:]]*[_[:alnum:]]+=' (note that \w is not portable). That's still no fool-proof but probably more reliable. The next big issue would be lines like ENVVAR=value some-command... – Stéphane Chazelas Jun 09 '14 at 07:05
4

You should do this with three scripts:

cat ./script/init_vars.sh
    variable_1=value_1
    variable_2=value_2
    variable_3=value_3

cat ./script/module_1.sh
    . ./script/init_vars.sh
    printf %s\\n "$variable_1"

cat ./script/module_2.sh
    . ./script/init_vars.sh
    printf %s\\n "$variable_1"

If your files looked like ^that^ then you'd be able to do this a lot easier - without relying on regexes. Running either module_1.sh or module_2.sh would output:

value_1
mikeserv
  • 58,310
  • My problem is that all of my variables and commands are inside one script. Nevertheless, I tried implementing your code. It works, too! Thanks @mikeserv. – Miguel Roque Jun 09 '14 at 05:14
  • @MiguelRoque - well, then maybe you should use regexes - but just once to get something like this. Then go through and check it to make sure it'll work and stick to the modular scheme from then on. Otherwise - and this is the real problem with the other solutions - you're doomed to break script 2 everytime you modify script 1. It's about as brittle as you can get. And what if $var1 is defined twice in script 1 like: var1=something ; test "$var1" ||\nvar1=something_else? What value do you get then? – mikeserv Jun 09 '14 at 06:38
-1

Use source to read the file variable in another shell file.

Suppose your variable var1 is initialised in /pathtoFile1/file1.sh

var1='Sridhar'

In another script file2.sh:

source /pathtoFile1/file1.sh
var2=$var1

Now var2 contains var1 value

  • Sourcing file1.sh will execute any commands in it. The OP specifically stated that they don't want that to happen. – JigglyNaga Dec 21 '18 at 11:15