如何列出bash中所有非环境变量?

如何列出bash中所有非环境变量?

我想要echoBash 3.2.52 中的所有非环境变量(所有自我声明的变量)。

这个打印所有变量的命令给了我我无法理解的输出,在我看来,这与set -x && clear -r我已经工作的模式相冲突。

diff -U 1 <(set -o posix ; set |cut -d= -f1) <(
    exec bash -ic 'set -o posix ; set' | cut -d= -f1)  |
        grep '^[-][^-]'                                |
        cut -d- -f2                                    |
        grep -vE '^(COLUMNS|HISTFILESIZE|HISTSIZE|LINES|PIPESTATUS)$'

我需要一个echoor printf(或任何其他“更简单”)操作来获得这样的列表。
如果在这个版本的 Bash 中可能的话,如何实现呢?

答案1

GNU 并行包括env_parallel.部分env_parallel列出了支持的 shell 的所有变量。

对于bash这段代码是:

_names_of_VARIABLES() {
    compgen -A variable
}
_bodies_of_VARIABLES() {
    typeset -p "$@"
}

因此,给定所有变量,我们需要找出哪些变量是由用户设置的。我们通过对给定版本的所有变量进行硬编码来做到这一点bash,但这不是非常未来的证明,因为bash可能在未来版本中设置更多变量(是$BASH_MYVAR由用户设置还是由未来版本设置bash?)。

因此,env_parallel要求您定义一个干净的环境,并env_parallel --session在其中运行。这将$PARALLEL_IGNORED_NAMES通过列出之前定义的名称(使用上面的代码)来设置。

当稍后在用户设置了变量的环境中运行时,很容易看出干净环境和当前环境之间的差异。

env_parallel --session可以为每个会话定义一个干净的环境,但如果您希望有一个可以跨会话使用的参考环境,只需将变量列表保存到文件中即可。所以:

# In clean envronment
compgen -A variable > ~/.clean-env-vars

# In environment with user defined vars
compgen -A variable | grep -Fxvf ~/.clean-env-vars

例如:

#!/bin/bash

# In clean envronment
compgen -A variable > ~/.clean-env-vars

myvar=4
yourvar=3

# In environment with user defined vars
compgen -A variable | grep -Fxvf ~/.clean-env-vars

# This prints:
# myvar
# yourvar
# PIPESTATUS (which is set when running a pipe)

答案2

将其添加到您的~/.bashrc

pre () {
    set -o posix;set > /tmp/tmp-original-envs
}

post () {
    set -o posix;set > /tmp/tmp-new-envs
    diff /tmp/tmp-original-envs /tmp/tmp-new-envs | grep -v BASH_LINENO | grep -v FUNCNAME | grep '>'
}

pre然后在修改之前和post之后运行

例子:

[localhost]$ pre
[localhost]$ test=new
[localhost]$ post
> test=new
[localhost]$ 

答案3

根据您的需求,一种简单的解决方案可能是:

  1. 在修改之前使用set > tmp或保存当前变量set > /tmp/current
  2. 您是否修改/运行您的应用程序
  3. diff -u <(cat tmp) <(set)提取用or修改的内容
diff -u <(cat tmp) <(set) | tail -n +3 | grep -v PIPESTATUS | grep -v "_=" | grep -E "^\+"

在哪里:

tail -n +3:删除 diff 命令的第一行不需要的行

grep -v PIPESTATUS | grep -v "_=": 删除不需要的变量

grep -E "^\+":仅显示所需/需要的更改

选择:

diff -u <(set -o posix; set) <(bash -lc 'set -o posix; set') | grep -E "^\+"

笔记:

在您的脚本中,请注意,exec完全替换由此启动的进程可能会干扰您想要实现的目标

答案4

笨拙的、仅 bash 的解决方案:

(setn(){
   set | sed '/^{/,/^}/d;/=/!d;/^BASH[A-Z_]*=\|^PPID=\|^SHLVL=\|^PIPESTATUS=\|^HISTSIZE=\|^HISTFILESIZE=\|^_[a-z_]*=/d' | sort
}
export -f setn
comm -23 <(setn) <("$BASH" -ic setn))

您可能还必须通过sed(或使BASH..模式更严格)过滤掉其他变量。应该/_[a-z_]*=/排除由可编程补全定义的变量,例如_backup_glob_xspecs;这也可以变得更加严格。

bash将打印格式中包含有趣字符的变量值$'...',因此您必须处理该问题:

foo='
bar
baz
'
...
foo=$'\nbar\nbaz\n'

bash不会从 envvars 创建 shell 变量名字包含换行符,所以没有办法通过这样的技巧来破解这个黑客。

相关内容