如何列出在bash脚本中声明的variables?

在我的bash脚本中,有很多variables,我必须做些什么来保存它们。 我的问题是如何列出在我的脚本中声明的所有variables,并得到像这样的列表:

VARIABLE1=abc VARIABLE2=def VARIABLE3=ghi 

set将输出variables,不幸的是它也会输出函数定义。

幸运的是POSIX模式只输出variables:

 ( set -o posix ; set ) | less 

pipe道less ,或redirect到你想要的选项。

所以要获取在脚本中声明的variables:

 ( set -o posix ; set ) >/tmp/variables.before source script ( set -o posix ; set ) >/tmp/variables.after diff /tmp/variables.before /tmp/variables.after rm /tmp/variables.before /tmp/variables.after 

(或者至less基于这个:-))

 compgen -v 

它列出了所有variables,包括本地variables。 我从bash中学到了:获取名称与特定模式匹配的variables列表 ,并在脚本中使用它。

 for i in _ {a..z} {A..Z}; do eval "echo \${!$i@}" ; done | xargs printf "%s\n" 

这必须打印所有的shellvariables名称。 您可以在获取文件之前和之后获得一个列表,就像使用“set”来区分哪些variables是新的(如其他答案所述)。 但是请记住,使用diff进行过滤可以过滤掉一些您需要但在提供文件之前已经存在的variables。

在你的情况下,如果你知道你的variables的名字是以“VARIABLE”开始的,那么你可以获得你的脚本的源代码并执行:

 for var in ${!VARIABLE@}; do printf "%s%q\n" "$var=" "${!var}" done 

更新:对于纯粹的BASH解决scheme(不使用外部命令):

 for i in _ {a..z} {A..Z}; do for var in `eval echo "\\${!$i@}"`; do echo $var # you can test if $var matches some criteria and put it in the file or ignore done done 

如果可以后处理(如前所述),则可以在脚本的开始和结尾处(每个脚本分别对应不同的文件)进行一次set调用,然后对这两个文件执行差异操作。 意识到这仍然会包含一些噪音。

你也可以通过编程来完成。 为了将输出限制在当前范围内,必须实现一个包装到variables的创build。 例如

 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 

收益率

 VAR1=abc VAR2=bcd VAR3=cde 

根据上面的一些答案,这对我有效:

 before=$(set -o posix; set | sort); 

源文件

 comm -13 <(printf %s "$before") <(set -o posix; set | sort | uniq) 

尝试使用脚本(让我们称之为“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,和:

  ls_vars your-script.sh > vars.files.save 

从安全angular度来看,@ akostadinov的回答或者@ JuvenXu的回答要比依赖set命令的非结构化输出要好,这是由于以下潜在的安全缺陷:

 #!/bin/bash function doLogic() { local COMMAND="${1}" if ( set -o posix; set | grep -q '^PS1=' ) then echo 'Script is interactive' else echo 'Script is NOT interactive' fi } doLogic 'hello' # Script is NOT interactive doLogic $'\nPS1=' # Script is interactive 

上面的函数doLogic使用set来检查variablesPS1的存在,以确定脚本是否是交互式的(不要介意这是否是实现这个目标的最好方法;这只是一个例子)。

但是, set的输出是非结构化的,这意味着任何包含换行符的variables都可能完全污染结果。

这当然是一个潜在的安全风险。 相反,使用Bash支持间接variables名称扩展或compgen -v

试试这个: set | egrep "^\w+=" set | egrep "^\w+=" (有或没有pipe道)

首先提出的解决scheme, ( set -o posix ; set ) | less ( set -o posix ; set ) | less ,工作但有一个缺点:它将控制代码传送到terminal,所以它们不能正确显示。 例如,如果有(可能) IFS=$' \t\n'variables,我们可以看到:

 IFS=' ' 

…代替。

我的egrep解决scheme正确地显示了这个(以及其他类似的)

我以前可能已经把答案偷走了 ……无论如何,它们的function稍有不同:

  ## # usage source bin/nps-bash-util-funcs # doEchoVars doEchoVars(){ # if the tmp dir does not exist test -z ${tmp_dir} && \ export tmp_dir="$(cd "$(dirname $0)/../../.."; pwd)""/dat/log/.tmp.$$" && \ mkdir -p "$tmp_dir" && \ ( set -o posix ; set )| sort >"$tmp_dir/.vars.before" ( set -o posix ; set ) | sort >"$tmp_dir/.vars.after" cmd="$(comm -3 $tmp_dir/.vars.before $tmp_dir/.vars.after | perl -ne 's#\s+##g;print "\n $_ "' )" echo -e "$cmd" }