如何在bash中仅打印定义的变量(shell和/或环境变量)


57

set如果不带参数调用bash内置命令,则将打印所有shell和环境变量,以及所有已定义的函数。这使得输出对于人类来说是无法使用的,并且难以实现grep

如何使bash内置命令set仅打印变量而不打印函数?

还有其他仅打印shell变量而不显示功能的命令吗?

注意:bash区分shell变量和环境变量。在此处查看环境变量与bash中导出的环境变量之间的区别

Answers:


51

“还有其他命令仅显示shell变量,而没有功能吗?”

在man bash中,SHELL BUILTIN COMMANDS部分(在set部分中)说:“在posix模式下,仅列出了shell变量。”

(set -o posix; set)

注意:()语法会产生一个子shell,如果您不喜欢分叉,请使用更详细的版本

set -o posix; set; set +o posix

1
迄今为止最好的解决方案
Ruslan 2014年

1
有很多以开头的通常不感兴趣的变量_,这些变量很容易摆脱:(set -o posix ; set | grep -v ^_)
hyde14 2014年

这么长时间一直困扰着我!如果您有多行值,仅收起以_开头的行是不够的,它仍将保留该值的内容。由于set按顺序打印行,所有_行都将在末尾,因此您可以使用以下命令简单地剪切第一行_之后的结果:set -o posix; set | sed -e '/^_/,$d'; set +o posix;
Scott

1
请注意:中的括号很重要(set -o posix; set)。如果没有括号,则当前的Bash shell的行为将更改为与Posix标准匹配。(Dunno这意味着什么,但看起来很重要。)使用括号将Bash保持不变。
约翰·雷德

1
副作用:设置POSIXLY_CORRECT=y,并增加了posix$SHELLOPTS
汤姆·黑尔

31

以下是一些解决方法:

$ comm -3 <(declare | sort) <(declare -f | sort)

分解:

  1. declare 打印每个定义的变量(是否导出)和函数。
  2. declare -f 仅打印功能。
  3. comm -3将会删除两者共同的所有行。实际上,这将删除功能,仅保留变量。

仅打印未导出的变量:

$ comm -3 <(comm -3 <(declare | sort) <(declare -f | sort)) <(env | sort)

另一个解决方法:

$ declare -p

这只会打印变量,但具有一些难看的属性。

declare -- BASH="/bin/bash"
declare -ir BASHPID=""
declare -A BASH_ALIASES='()'
declare -a BASH_ARGC='()'
...

您可以使用... cut删除属性。

$ declare -p | cut -d " " -f 3

缺点之一是IFS的值被解释而不是显示。

相比:

$ comm -3 <(declare | sort) <(declare -f | sort)
...
IFS=$' \t\n'
...
$ declare -p | cut -d " " -f 3
...
IFS="
"
...

由于"一行中只有一行,因此很难将该输出用于进一步处理。也许可以采取一些IFS-fu来防止这种情况。


另一个解决方法,使用compgen

$ compgen -v

内置的bash compgen旨在用于完成脚本中。为此,compgen -v列出所有定义的变量。缺点:它仅列出变量名称,而不列出值。

这是一个可以列出值的技巧。

$ compgen -v | while read var; do printf "%s=%q\n" "$var" "${!var}"; done

优点:它是纯bash解决方案。缺点:由于的解释,一些值被弄乱了printf。管道和/或循环的子外壳也添加了一些额外的变量。


没有declare ...| cut变量的属性,管道会中断吗?我猜--是在这种情况下使用的,但我仍然不安。sed可能更安全,即declare -p | sed 's/^.* \([^ ]\+\)$/\1/'
jmtd 2011年

+1 compgen:)
RSFalcon7'3

13

typeset奇怪的是,内建函数具有仅显示函数(-f)而不仅显示参数的选项。幸运的是,typeset(或set)在所有函数之前显示所有参数,函数和参数名称不能包含换行符或等号,并且参数值中的换行符用引号引起来(它们显示为\n)。因此,您可以在不包含等号的第一行处停止:

set | awk -F '=' '! /^[0-9A-Z_a-z]+=/ {exit} {print $1}'

这仅显示参数名称。如果需要这些值,请更改print $1print $0

请注意,这将打印所有参数名称(此处是参数和变量的同义词),而不仅仅是环境变量(“环境变量”与“导出参数”的同义词)。

还要注意,这假设没有名称与bash对参数名称的约束不匹配的环境变量。这些变量不能在bash内部创建,但是可以在bash启动时从环境中继承:

env 'foo ()
{
  =oops' bash

很好的解决方案!我什至没有想到只是停在没有'='的第一行。+1
史蒂文D

等效地,使用sed: set | sed '/=/!Q'
Toby Speight,

7

我不确定如何使set仅打印变量。但是,通过查看的输出set,我可以得出以下似乎仅包含变量的内容:

$ set | grep "^\([[:alnum:]]\|[[:punct:]]\)\+=" 

基本上,我正在寻找以字母,数字或标点符号开头,后跟“ =”的行。从我看到的输出中,它捕获了所有变量;但是,我怀疑这是否可移植。

如果如您的标题所示,如果您希望从此列表中减去导出的变量,从而获得未导出的变量的列表,则可以执行以下操作

$ set | grep "^\([[:alnum:]]\|[[:punct:]]\)\+=" | sort > ./setvars && env | sort | comm -23 ./setvars - 

为了稍微分解一下,这是它的作用:

  1. set | grep "^\([[:alnum:]]\|[[:punct:]]\)\+=" | sort > ./setvars :这有望获得所有变量(如前所述),对其进行排序,然后将结果粘贴到文件中。
  2. && env | sort:上一条命令完成后,我们将调用env并对其输出进行排序。
  3. | comm -23 ./setvars -:最后,我们管的有序输出envcomm,并使用-23选项打印所特有的第一个参数的线,在这种情况下,唯一我们从一组输出线。

完成后,您可能需要清理使用命令创建的临时文件 rm ./setvars


命令的问题不是可移植性(当然,它特定于bash,但是grep方面没有问题)。问题是您在函数定义中抓了几行。Bash缩进了大多数功能代码,但并非全部缩进,特别是在此文档中的文本不缩进(f () {|cat <<EOF|foo=bar|EOF|}其中|表示换行符)。
吉尔斯(Gilles)2010年


2

试试命令printenv:

$printenv

6
printenv和env仅打印导出的(环境)变量,而不打印非导出的(shell)变量。
Lri 2013年

@Lri谢谢!我想知道如何仅打印导出的变量。
马克·斯图尔特


0

对比干净的外壳以确保rc脚本中的var也被排除在外

## get mostly local vars
diff_env(){
    diff <(bash -cl 'set -o posix && set') \
        <(set -o posix && set && set +o posix) | \
        grep -E "^>|^\+" | \
        grep -Ev "^(>|\+|\+\+) ?(BASH|COLUMNS|LINES|HIST|PPID|SHLVL|PS(1|2)|SHELL|FUNC)" | \
        sed -r 's/^> ?|^\+ ?//'
}

的版本comm太复杂了


0

公认的答案是伟大的。我提供了一种不涉及设置POSIX模式的替代方法:

这是我一直在使用的将函数状态存储到文件中的技术,因此我以后可以继续进行操作。第一个产生状态转储,第二个仅产生变量名列表。

set 2>/dev/null | while read a; do [[ $a == *=* ]] || break; echo $a; done 

set 2>/dev/null | while read a; do [[ $a == *=* ]] || break; echo ${a/=*}; done 

两者都通过转储行来工作,直到找到一个没有'='字符的字符为止,这在列出第一个函数时发生。后者取消了任务。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.