bash 内置命令set
,如果不带参数调用,将打印所有 shell 和环境变量,以及所有定义的函数。这使得输出无法供人类使用并且难以使用grep
。
如何使 bash 内置命令set
仅打印变量而不打印函数?
是否还有其他命令只打印 shell 变量而不打印函数?
注意:bash 区分 shell 变量和环境变量。看这里bash中环境变量和导出环境变量的区别
答案1
“还有其他命令只打印 shell 变量而不打印函数吗?”
在 man bash 中,SHELL BUILTIN COMMANDS 部分(在 set 部分)中显示:“在 posix 模式下,仅列出 shell 变量。”
(set -o posix; set)
注意:()
语法会生成一个子 shell,如果您不喜欢分叉,只需使用更详细的版本
set -o posix; set; set +o posix
答案2
以下是一些解决方法:
$ comm -3 <(declare | sort) <(declare -f | sort)
分解:
declare
打印每个定义的变量(导出或未导出)和函数。declare -f
仅打印函数。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
。此外,管道和/或循环中的子 shell 添加了一些额外的变量。
答案3
奇怪的是,内置函数typeset
有一个选项只显示函数(-f
),但不只显示参数。幸运的是,typeset
(或set
) 显示所有函数之前的所有参数,函数和参数名称不能包含换行符或等号,并且参数值中的换行符被引用(它们显示为\n
)。因此,您可以在不包含等号的第一行处停止:
set | awk -F '=' '! /^[0-9A-Z_a-z]+=/ {exit} {print $1}'
这只打印参数名称;如果您想要这些值,请更改print $1
为print $0
.
请注意,这会打印所有参数名称(此处参数和变量同义使用),而不仅仅是环境变量(“环境变量”与“导出的参数”同义)。
另请注意,这假设不存在名称与 bash 对参数名称的约束不匹配的环境变量。这些变量不能在 bash 内部创建,但可以在 bash 启动时从环境继承:
env 'foo ()
{
=oops' bash
答案4
只需使用命令即可env
。它不打印函数。