How to list variables declared in script in bash?

后端 未结 14 921
走了就别回头了
走了就别回头了 2020-11-28 20:03

In my script in bash, there are lot of variables, and I have to make something to save them to file. My question is how to list all variables declared in my script and get l

相关标签:
14条回答
  • 2020-11-28 20:12

    Try using a script (lets call it "ls_vars"):

      #!/bin/bash
      set -a
      env > /tmp/a
      source $1
      env > /tmp/b
      diff /tmp/{a,b} | sed -ne 's/^> //p'
    

    chmod +x it, and:

      ls_vars your-script.sh > vars.files.save
    
    0 讨论(0)
  • 2020-11-28 20:13

    If you're only concerned with printing a list of variables with static values (i.e. expansion doesn't work in this case) then another option would be to add start and end markers to your file that tell you where your block of static variable definitions is, e.g.

    #!/bin/bash
    
    # some code
    
    # region variables
    VAR1=FOO
    VAR2=BAR
    # endregion
    
    # more code
    

    Then you can just print that part of the file.

    Here's something I whipped up for that:

    function show_configuration() {
       local START_LINE=$(( $(< "$0" grep -m 1 -n "region variables" | cut -d: -f1) + 1 ))
       local END_LINE=$(( $(< "$0" grep -m 1 -n "endregion" | cut -d: -f1) - 1 ))
       < "$0" awk "${START_LINE} <= NR && NR <= ${END_LINE}"
    }
    
    

    First, note that the block of variables resides in the same file this function is in, so I can use $0 to access the contents of the file.

    I use "region" markers to separate different regions of code. So I simply grep for the "variable" region marker (first match: grep -m 1) and let grep prefix the line number (grep -n). Then I have to cut the line number from the match output (splitting on :). Lastly, add or subtract 1 because I don't want the markers to be part of the output.

    Now, to print that range of the file I use awk with line number conditions.

    0 讨论(0)
  • 2020-11-28 20:15

    If you can post-process, (as already mentioned) you might just place a set call at the beginning and end of your script (each to a different file) and do a diff on the two files. Realize that this will still contain some noise.

    You can also do this programatically. To limit the output to just your current scope, you would have to implement a wrapper to variable creation. For example

    store() {
        export ${1}="${*:2}"
        [[ ${STORED} =~ "(^| )${1}($| )" ]] || STORED="${STORED} ${1}"
    }
    
    store VAR1 abc
    store VAR2 bcd
    store VAR3 cde
    
    for i in ${STORED}; do
        echo "${i}=${!i}"
    done
    

    Which yields

    VAR1=abc
    VAR2=bcd
    VAR3=cde
    
    0 讨论(0)
  • 2020-11-28 20:16

    Here's something similar to the @GinkgoFr answer, but without the problems identified by @Tino or @DejayClayton, and is more robust than @DouglasLeeder's clever set -o posix bit:

    + function SOLUTION() { (set +o posix; set) | sed -ne '/^\w\+=/!q; p;'; }
    

    The difference is that this solution STOPS after the first non-variable report, e.g. the first function reported by set

    BTW: The "Tino" problem is solved. Even though POSIX is turned off and functions are reported by set, the sed ... portion of the solution only allows variable reports through (e.g. VAR=VALUE lines). In particular, the A2 does not spuriously make it into the output.

    + function a() { echo $'\nA2=B'; }; A0=000; A9=999; 
    + SOLUTION | grep '^A[0-9]='
    A0=000
    A9=999
    

    AND: The "DejayClayton" problem is solved (embedded newlines in variable values do not disrupt the output - each VAR=VALUE get a single output line):

    + A1=$'111\nA2=222'; A0=000; A9=999; 
    + SOLUTION | grep '^A[0-9]='
    A0=000
    A1=$'111\nA2=222'
    A9=999
    

    NOTE: The solution provided by @DouglasLeeder suffers from the "DejayClayton" problem (values with embedded newlines). Below, the A1 is wrong and A2 should not show at all.

    $ A1=$'111\nA2=222'; A0=000; A9=999; (set -o posix; set) | grep '^A[0-9]='
    A0=000
    A1='111
    A2=222'
    A9=999
    

    FINALLY: I don't think the version of bash matters, but it might. I did my testing / developing on this one:

    $ bash --version
    GNU bash, version 4.4.12(1)-release (x86_64-pc-msys)
    

    POST-SCRIPT: Given some of the other responses to the OP, I'm left < 100% sure that set always converts newlines within the value to \n, which this solution relies upon to avoid the "DejayClayton" problem. Perhaps that's a modern behavior? Or a compile-time variation? Or a set -o or shopt option setting? If you know of such variations, please add a comment...

    0 讨论(0)
  • 2020-11-28 20:24

    A little late to the party, but here's another suggestion:

    #!/bin/bash
    
    set_before=$( set -o posix; set | sed -e '/^_=*/d' )
    
    # create/set some variables
    VARIABLE1=a
    VARIABLE2=b
    VARIABLE3=c
    
    set_after=$( set -o posix; unset set_before; set | sed -e '/^_=/d' )
    diff  <(echo "$set_before") <(echo "$set_after") | sed -e 's/^> //' -e '/^[[:digit:]].*/d'
    

    The diff+sed pipeline command line outputs all script-defined variables in the desired format (as specified in the OP's post):

    VARIABLE1=a
    VARIABLE2=b
    VARIABLE3=c
    
    0 讨论(0)
  • 2020-11-28 20:26
    compgen -v
    

    It lists all variables including local ones. I learned it from Get list of variables whose name matches a certain pattern, and used it in my script.

    0 讨论(0)
提交回复
热议问题