8

When set command is used without any options, it displays the names and values of all shell variables and functions.

We want to display only the variables and avoid the functions from the output.

Rui F Ribeiro
  • 56,709
  • 26
  • 150
  • 232

4 Answers4

16

As I already stated in a comment, env doesn't fit the requirement as it only shows exported variables.

Processing set output to filter out anything that doesn't look like a variable definition is an unreliable hack. You will in particular miss a part of variables which value contains a line feed. Even worst, a carefully written function can make appear fake variables definitions.

The simplest solution is to switch temporarily to the POSIX mode where functions are not considered to be (kind of) variables:

set -o posix
set
set +o posix

There is however an issue if your default mode is already POSIX, or if you want that command to work whatever POSIX mode the shell is set to.

In such case, here is a workaround:

(set -o posix;set)

This only set the POSIX mode for the set builtin executed in a subshell and the parent shell mode stay unaffected.

jlliagre
  • 61,204
  • @jiliagre I guess even this would work set | grep -E '^\S+=\S'....right @terdon? – frp farhan Dec 06 '16 at 12:45
  • @FarhanPatel not for everything. See jlliagre's comment on my answer. This approach is better. – terdon Dec 06 '16 at 18:32
  • POSIX mode has the drawback of outputting multiline variables on multiple lines. While without POSIX mode, set outputs multiline variables as foobar=$'foo\nbar\nbaz' on a single line. Which is easier to parse then. – Antoine Pinsard Oct 14 '17 at 09:03
4

While the simplest solution is to use env instead of set, env doesn't give all existing variables but only those that would be passed to any process started with env (so no unexported variables, for example). Another approach is to search the output of set for lines that have a string of non-whitespace, an = and then another string of non-whitespace characters:

set | grep -E '^\S+=\S' 

However, this will miss any variables set to a multiline value (like IFS whose default value includes a \n).

terdon
  • 242,166
  • 1
    @jlliagre indeed it is, there was a PEBKAC there. What can it miss though? Can you think of an example? – terdon Dec 06 '16 at 12:28
  • 2
    With the previous commands, you were missing by design all legitimate variables with names starting with an underscore. You are still missing a part of multiline content variables (e.g. IFS) so the output of your command is not parseable. Finally, you might display fake variables from function definitions. – jlliagre Dec 06 '16 at 12:48
  • Not to mention you run an external command while the shell is able to provide the already filtered output a more efficient way. – jlliagre Dec 06 '16 at 12:50
  • @jlliagre yes indeed. Very true for multiline vars, hadn't thought of that. But set doesn't print functions. At least not on my system. What kind of fake variables are you thinking of? – terdon Dec 06 '16 at 18:32
  • Bash set builtin print functions, that's the whole point of the OP question. Here is an example of such a fake variable: f() { a="a[ENTER]fubar=/tmp/gotcha[ENTER]b"; } . In fact, the same trick might also be used with multiline variables. – jlliagre Dec 06 '16 at 20:32
  • @jlliagre I had first thought you were absolutely correct, then I tested by defining a function, running set and grepping for it, and I failed to find it. Now I'm on a different system, tested again and did find it so I'm back to thinking you were absolutely correct in the first place. I'll go back to work tomorrow and try it again. I probably just did something stupid but in my defense, I did test! – terdon Dec 06 '16 at 20:53
  • You might have been missing to see function definitions inset output because you might have been running bash in POSIX mode, or running dash, ksh or whatever shell variant. – jlliagre Dec 06 '16 at 22:25
  • Actually this solution works better for me because without posix mode, bash outputs variable definitions in one line even for multiline variables. – Antoine Pinsard Oct 14 '17 at 09:00
3

For some odd reason, declare -p seems to list only variables:

$ declare -p
declare -x ANT_HOME="/usr/share/apache-ant"
declare -- BASH="/usr/bin/bash"
declare -r BASHOPTS="checkwinsize:cmdhist:complete_fullquote:expand_aliases:extglob:extquote:force_fignore:histappend:interactive_comments:progcomp:promptvars:sourcepath"
declare -ir BASHPID
declare -A BASH_ALIASES=()
declare -a BASH_ARGC=()
declare -a BASH_ARGV=()
declare -A BASH_CMDS=()
...

Of course, this has the disadvantage that it outputs declare commands that can recreate the variable with all its attributes. Depending on what you intend to do with the output, that might actually be useful.

muru
  • 72,889
2

I'm not sure, but the cow would consider something.

 _____
( env )
 -----
        o   ^__^
         o  (oo)\_______
            (__)\       )\/\
                ||----w |
                ||     ||

In other words, just use env instead.


I guess she's just read jilliagre's comment.

 ________________________________
/ But it will only show exported \
\ variables!                     /
 --------------------------------
        \   ^__^
         \  (!!)\_______
            (__)\       )\/\
             !! ||----w |
                ||     ||