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

les*_*ana 62 bash environment-variables

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

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

是否有其他命令只打印 shell 变量而不打印函数?

注意:bash 区分 shell 变量和环境变量。请参阅此处环境变量和 bash 中导出的环境变量之间的差异

小智 58

“是否有其他命令只打印 shell 变量,而不打印函数?”

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

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

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

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

  • **副作用**:设置`POSIXLY_CORRECT=y`并将`posix`添加到`$SHELLOPTS` (3认同)
  • 迄今为止最好的解决方案 (2认同)
  • 有一堆通常无趣的以 `_` 开头的变量,很容易删除:`(set -o posix ; set | grep -v ^_)` (2认同)
  • 请注意:括号在`(set -o posix; set)`中很重要。如果没有括号,当前 Bash shell 的行为将被更改以匹配 Posix 标准。(不知道这是什么意思,但看起来很重要。)有了括号,Bash 保持不变。 (2认同)
  • 另一种触发 POSIX 行为的方法:`(POSIXLY_CORRECT= set)` (2认同)

les*_*ana 33

以下是一些解决方法:

$ comm -3 <(declare | sort) <(declare -f | sort)
Run Code Online (Sandbox Code Playgroud)

分解:

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

仅打印未导出的变量:

$ comm -3 <(comm -3 <(declare | sort) <(declare -f | sort)) <(env | sort)
Run Code Online (Sandbox Code Playgroud)

另一种解决方法:

$ declare -p
Run Code Online (Sandbox Code Playgroud)

这只会打印变量,但有一些丑陋的属性。

declare -- BASH="/bin/bash"
declare -ir BASHPID=""
declare -A BASH_ALIASES='()'
declare -a BASH_ARGC='()'
...
Run Code Online (Sandbox Code Playgroud)

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

$ declare -p | cut -d " " -f 3
Run Code Online (Sandbox Code Playgroud)

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

相比:

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

这使得使用该输出进行进一步处理变得非常困难,因为"只有一行。也许可以做一些 IFS-fu 来防止这种情况发生。


另一种解决方法,使用compgen

$ compgen -v
Run Code Online (Sandbox Code Playgroud)

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

这是一个 hack 也列出了这些值。

$ compgen -v | while read var; do printf "%s=%q\n" "$var" "${!var}"; done
Run Code Online (Sandbox Code Playgroud)

优点:它是一个纯粹的 bash 解决方案。缺点:由于通过printf. 来自管道和/或循环的子外壳也添加了一些额外的变量。


Gil*_*il' 13

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

set | awk -F '=' '! /^[0-9A-Z_a-z]+=/ {exit} {print $1}'
Run Code Online (Sandbox Code Playgroud)

这仅打印参数名称;如果需要这些值,请更改print $1print $0.

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

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

env 'foo ()
{
  =oops' bash
Run Code Online (Sandbox Code Playgroud)

  • 等效地,使用 sed:`set | sed '/=/!Q'` (2认同)

Ste*_*n D 7

我不确定如何制作set仅打印变量。然而,通过查看 的输出set,我能够想出以下似乎只获取变量的内容:

$ set | grep "^\([[:alnum:]]\|[[:punct:]]\)\+=" 
Run Code Online (Sandbox Code Playgroud)

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

如果,正如你的标题所暗示的,你想从这个列表中减去导出的变量,从而得到一个非导出变量的列表,那么你可以做这样的事情

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

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

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

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


unx*_*nut 6

只需使用命令env。它不打印功能。

  • 如果在脚本中使用,它会这样做。 (2认同)