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

lau*_*iys 91 variables bash

在我的bash脚本中,有很多变量,我必须做些什么来将它们保存到文件中.我的问题是如何列出我的脚本中声明的所有变量并得到如下列表:

VARIABLE1=abc
VARIABLE2=def
VARIABLE3=ghi
Run Code Online (Sandbox Code Playgroud)

Dou*_*der 142

set 将输出变量,遗憾的是它也将输出定义的函数.

幸运的是POSIX模式只输出变量:

( set -o posix ; set ) | less
Run Code Online (Sandbox Code Playgroud)

管道less,或重定向到您想要的选项.

因此,要获取仅在脚本中声明的变量:

( 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
Run Code Online (Sandbox Code Playgroud)

(或至少基于此的东西:-))

  • 不使用临时文件:`VARS ="\`set -o posix; set \`"; 源脚本; SCRIPT_VARS ="\`grep -vFe"$ VARS"<<<"$(set -o posix; set)"| grep -v ^ VARS = \`"; unset VARS;`.这也将以准备保存的格式输出变量.该列表将包括脚本更改的变量(取决于是否需要) (7认同)
  • @ErikAronesty 如果您希望能够使用 `source` 重新创建环境,您应该能够使用 `declare -p` 的输出来实现。 (2认同)
  • 如果你想比较diff(或任何类似命令)之前和之后的环境而不使用临时文件,你可以使用以下命令:`before = $(set -o posix; set); dosomestuff; diff <(echo"$ before")<(set -o posix; set)` (2认同)
  • @Caesar 不,我只尝试过非空数组。如果是空数组,你是对的——它们不会被打印。 (2认同)
  • 对于任何 zsh 用户: posix 选项在 zsh 中不起作用(`set: no such option: posix`) - 我们必须在 /bin/bash 中执行命令。 (2认同)

小智 39

compgen -v
Run Code Online (Sandbox Code Playgroud)

它列出了所有变量,包括本地变量.我从bash中学到了它:获取名称与某个模式匹配的变量列表,并在我的脚本中使用它.

  • 遗憾的是,`compgen -v` 还列出了本地未设置的全局变量。不确定这是一个长期存在的错误还是所需的行为。 (2认同)

ako*_*nov 10

for i in _ {a..z} {A..Z}; do eval "echo \${!$i@}" ; done | xargs printf "%s\n"
Run Code Online (Sandbox Code Playgroud)

这必须打印所有shell变量名称.您可以在获取文件之前和之后获取列表,就像使用"set"来区分哪些变量是新的(如其他答案中所述).但请记住,使用diff进行过滤可以过滤掉您需要但在获取文件之前存在的一些变量.

在您的情况下,如果您知道变量的名称以"VARIABLE"开头,那么您可以获取脚本并执行以下操作:

for var in ${!VARIABLE@}; do
   printf "%s%q\n" "$var=" "${!var}"
done
Run Code Online (Sandbox Code Playgroud)

更新:对于纯BASH解决方案(不使用外部命令):

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
Run Code Online (Sandbox Code Playgroud)

  • 啊,我应该读到 https://tldp.org/LDP/abs/html/parameter-substitution.html 的末尾,因为这就是它所描述的地方。 (4认同)
  • +1 和一个单行版本(带有单个 eval): `eval "printf '%q\n' $(printf ' "${!%s@}"' _ {a..z} {A..Z} )"` (3认同)
  • 哇!这个黑魔法‘"\\${!$i@}"`是什么?!我看到像 `echo "${!BASH_C@}"` 这样简单的东西会转储以 `BASH_C` 开头的所有变量,但为什么呢?`!` 是间接运算符,但是间接运算符是什么?我们最终列出了变量,而不是它们的值。到底是怎么回事!:) (2认同)

ezp*_*zpz 5

如果您可以进行后处理(如前所述),您可能只需set在脚本的开头和结尾处进行调用(每个调用到不同的文件)并对两个文件进行比较。请注意,这仍然会包含一些噪音。

您也可以通过编程来执行此操作。要将输出限制为当前范围,您必须实现变量创建的包装器。例如

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
Run Code Online (Sandbox Code Playgroud)

哪个产量

VAR1=abc
VAR2=bcd
VAR3=cde
Run Code Online (Sandbox Code Playgroud)


小智 5

基于上述一些答案,这对我有用:

before=$(set -o posix; set | sort);
Run Code Online (Sandbox Code Playgroud)

源文件

comm -13 <(printf %s "$before") <(set -o posix; set | sort | uniq) 
Run Code Online (Sandbox Code Playgroud)