Sign up ×
Unix & Linux Stack Exchange is a question and answer site for users of Linux, FreeBSD and other Un*x-like operating systems. It's 100% free, no registration required.

Lets supose some bash shell script like:

#!/bin/bash 
a=3
b=7
set -o posix
set

In this case, the execution of the set variable or some other of the commands to print environment variables (env,declare... etc) outputs my a and b variables, plus a lot of variables (and functions) from the environment (PATH, PWD, TEMP... etc).

Is there a way to print only those variables that have been defined during the script body?

share|improve this question
    
You probably want to filter against the export attribute. Look harder at typeset, probably it can do this, but I don't believe there is a posix portable method of doing so. Of course the simple solution is to track the variables you set in your script ... in your script... If your parent shell is bash, by the way, that would explain all of your unwanted env. some more simple shells will not have this issue - especially if invoked like env - script. –  mikeserv Dec 9 '14 at 8:09

3 Answers 3

Here's a portable means of getting a sorted list of all currently defined varnames:

v(){ set "${IFS+IFS=\$2}" "$IFS"; unset IFS
     set  $(set|sed -n '/^[_[:alpha:]][[:alnum:]]*=/s/=.*//p'|sort -u) "$@"
     while [ "$#" -gt 2 ] 
     do    eval '[ "${'$1'+1}" = 1 ]' && 
           echo "$1"; shift
     done; eval "$1"
}

That list is echoed to v()'s stdout - one name per line. Because it is sorted it is a good candidate for later comparison with a similarly generated list as you might do with comm or similar. The list intentionally excludes $IFS - and this is because - set or not - $IFS is always in effect and so must be a given anyway in such a list. That could be altered like:

set "${IFS+IFS=\$2}" "$IFS"; IFS='
'; set $(set|... 

...but that would only always include it in a list whether it were set or not - which brings me back to my previous point...

share|improve this answer

You can store the list of variables at the beginning of the script and compare it with the value somewhere during the script. Beware that the output of commands like set isn't built to be unambiguous: something like set | sed 's/=.*//' doesn't work with variables whose values contain newlines. (In bash, it actually does for string variables, but not for arrays, and it also displays function code.) I think that the following snippet reliably lists the currently defined variables (in alphabetical order, to boot):

variables=$(tmp=$(declare -p +F); declare () { echo "${2%%=*}"; }; eval "$tmp")

Thus, set initial_variables=… at the beginning of the script, and compare with the later value. You can use something other than echo to act on the list directly.

initial_variables=" $(tmp=$(declare -p +F); declare () { echo "${2%%=*}"; }; eval "$tmp") "
…
( tmp=$(declare -p +F)
  declare () {
    case "$initial_variables" in
      *" $2 "*) :;; # this variable was present initially
      *) eval "set -- \"\$$2\" \"\$2\""; echo "locally defined $2=$1";;
    esac
  }
)
share|improve this answer

A solution using comm based on storing all the variables before and after:

#!/bin/bash 

# Storing variables before:
set -o posix
set > $TMP/VariablesBefore.txt
sort $TMP/VariablesBefore.txt -o $TMP/VariablesBeforeSorted.txt

a=3
b=7

# Storing variables after:
set > $TMP/VariablesNow.txt
sort $TMP/VariablesNow.txt -o $TMP/VariablesNowSorted.txt

# Computing differences:
echo "The variables inside the script are: "
comm -3 $TMP/VariablesBeforeSorted.txt $TMP/VariablesNowSorted.txt

Well, there are still a few variables remaining like _ or BASH_LINENO, but this is the bet I have reached.

Note that this solution could not work in all cases, for example variables very long (KB), with new line codes, or variables including variable names. Thanks, MikeServ, for pointing.

share|improve this answer
    
I have tested it working with variables containing numbers, strings and pathnames. What do you mean by "working with names"? –  Sopalajo de Arrierez Dec 9 '14 at 8:27
    
Uh... no, they are just numbers and strings. It could be interesting to solve those cases you tell, @mikeserv. –  Sopalajo de Arrierez Dec 9 '14 at 9:10

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.