How to print only defined variables (shell and/or environment variables) in bash

"Are there other commands which prints only the shell variables, without the functions?"

In man bash, in section SHELL BUILTIN COMMANDS (in the set section) it says: "In posix mode, only shell variables are listed."

(set -o posix; set)

note: () syntax spawns a subshell, if you don't like forking just use the more verbose version

set -o posix; set; set +o posix

Here are some workarounds:

$ comm -3 <(declare | sort) <(declare -f | sort)

breakdown:

  1. declare prints every defined variable (exported or not) and function.
  2. declare -f prints only functions.
  3. comm -3 will remove all lines common to both. In effect this will remove the functions, leaving only the variables.

To only print variables which are not exported:

$ comm -3 <(comm -3 <(declare | sort) <(declare -f | sort)) <(env | sort)

Another workaround:

$ declare -p

This will only print the variables, but with some ugly attributes.

declare -- BASH="/bin/bash"
declare -ir BASHPID=""
declare -A BASH_ALIASES='()'
declare -a BASH_ARGC='()'
...

You can cut the attributes away using... cut:

$ declare -p | cut -d " " -f 3

One downside is that the value of IFS is interpreted instead of displayed.

compare:

$ comm -3 <(declare | sort) <(declare -f | sort)
...
IFS=$' \t\n'
...
$ declare -p | cut -d " " -f 3
...
IFS="
"
...

This makes it quite hard to use that output for further processing, because of that lone " in one line. Perhaps some IFS-fu can be done to prevent this.


Yet another workaround, using compgen:

$ compgen -v

The bash builtin compgen was meant to be used in completion scripts. To this end, compgen -v lists all defined variables. The downside: it lists only the variable names, not the values.

Here is a hack to also list the values.

$ compgen -v | while read var; do printf "%s=%q\n" "$var" "${!var}"; done

The advantage: it is a pure bash solution. The disadvantage: some values are messed up because of the interpretation through printf. Also the subshell from the pipe and/or the loop add some extra variables.


The typeset builtin strangely has an option to show functions only (-f) but not to show parameters only. Fortunately, typeset (or set) displays all parameters before all functions, function and parameter names cannot contain newlines or equal signs, and newlines in parameter values are quoted (they appear as \n). So you can stop at the first line that doesn't contain an equal sign:

set | awk -F '=' '! /^[0-9A-Z_a-z]+=/ {exit} {print $1}'

This only prints the parameter names; if you want the values, change print $1 to print $0.

Note that this prints all parameter names (parameters and variables are used synonymously here), not just environment variables (“environment variable” is synonymous with “exported parameters”).

Note also that this assumes there is no environment variable with a name that doesn't match bash's constraints on parameter names. Such variables cannot be created inside bash but can have been inherited from the environment when bash starts:

env 'foo ()
{
  =oops' bash