8

When writing bash scripts I like to write self contained functions which take an argument and perform operations based on that/those argument(s) rather than have global variables being declared in several different places in the code decreasing readability.

The issue arises when you have a function which needs to make use of several variables. Passing something like 10 variables to a function is just plain ugly and for that a simple associative array can be used.

If we want to declare those variables on an external file, the "source" command allows you to import them all in.

The issue then becomes, how do I list the variables declared ONLY inside this file so I can build my associative array with them? I have been able to use a combination of "compgen" and a loop to build associative arrays out of a list of variables but how does one list only the variables found inside the file, regardless of what they are called, so I can loop through them and build my array?

Alexandre Thenorio
  • 2,288
  • 3
  • 31
  • 50
  • 1
    I'd tend to suggest using an easy-to-parse comment format for your documentation (as done for doxygen, javadoc, and derivative tools). – Charles Duffy Nov 02 '15 at 23:00
  • 1
    You could always compare the output from `declare`/`set` before and after the sourcing of the config file? =) Or, if the config file is unique to that function just create the array directly. And if it isn't unique to the function then you need some way to only use the correct variables anyway so just write a "collect_args" function which takes the variable names the function expects, etc. – Etan Reisner Nov 02 '15 at 23:34
  • Thank you. @EtanReisner I think your suggestion may have to do as it seems I cannot find a better solution other than parsing the actual file – Alexandre Thenorio Nov 10 '15 at 17:52
  • You might want to look at https://github.com/threatgrid/declarative.bash actually. It might be useful to you. (I don't know anything about it I've just had it in a tab for a while to go back and look at.) – Etan Reisner Nov 10 '15 at 18:22
  • Would you mind responding to the answer? Do you need further help or does it not fit your needs maybe? – David Nov 20 '15 at 00:16
  • Hi David. Sorry for not looking into this earlier, I have been really busy but plan to look into the solution you posted after holidays as soon as I get some time. Thank you – Alexandre Thenorio Dec 10 '15 at 21:01

3 Answers3

2

You could do an egrep for some variable declaring syntax on your file and then get the variable name by cutting it, for example like this:

egrep '[a-zA-Z0-9"'\''\[\]]*=' /path/to/file |egrep -v '^#' |cut -d'=' -f1 |awk '{print $1}'

If you had a file with content like this

#!/bin/bash

A="test"

somerandomfunction () {
        echo "test function"
        B="test"
}

#C="test"

DEF="test"
GHI1="test"
JKL[1]="test"
JKL['a']="test"
JKL["b"]="test"

the output of the above command would look like this:

A
B
DEF
GHI1
JKL[1]
JKL['a']
JKL["b"]

Explanation of the commands:

  1. The first egrep searches for lines containing any number and combination of lowercase (a-z) and/or uppercase (A-Z) letters and/or square brackets (\[\]) and/or single ('\'') and/or double (") quotation marks followed by a =.
  2. The second egrep excludes lines beginning with a # since those are usually interpreted as comments and would not generate or set a variable.
  3. The cut command cuts away everything from the = to the line ending.
  4. The awk command prints the first occurence of something else than spaces or tabs and therefore effectively cuts away empty space in front of variable names.

The output of the command could be used in a loop or something like this:

for VAR in $(egrep '[a-zA-Z0-9"'\''\[\]]*=' /path/to/file |egrep -v '^#' |cut -d'=' -f1 |awk '{print $1}'); do
  eval echo "\$${VAR}"
done
David
  • 308
  • 1
  • 12
0

This is one way using awk:

egrep "*=" file |awk 'BEGIN{FS="="}{print $1}'|grep -v "#"|column -t

Explanation:

Since Variables will have "=" for assignment of values, using that as a pattern grep the "*=" from the file. once That done, i am using awk to declare the Field separator as "=" and printing out anything before it using $1. Column -t is just for aligning the output to left.

Hope it helps.

Smar
  • 8,109
  • 3
  • 36
  • 48
abhishek phukan
  • 751
  • 1
  • 5
  • 16
  • grep -v "#" is for leaving out commented variables. this can be ignored if you want the commented variables to be printed out as well – abhishek phukan Sep 19 '17 at 04:45
0

What about getting the variables directly from the file?

VARLIST=$(cut -d= -f1 file_with_variables)
Victor Henriquez
  • 1,399
  • 15
  • 26