我想要echo
Bash 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)$'
我需要一个echo
or 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
根据您的需求,一种简单的解决方案可能是:
- 在修改之前使用
set > tmp
或保存当前变量set > /tmp/current
- 您是否修改/运行您的应用程序
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 变量名字包含换行符,所以没有办法通过这样的技巧来破解这个黑客。