posix shell:打印环境变量名称列表(无值)


11

以与多种实现兼容的posix兼容方式,如何打印当前定义的环境变量列表而不包含它们的值?

在某些实现(mksh,freebsd / bin / sh)上,只需单独使用即可export

$ export
FOO2
FOO

但是对于其他一些实现(bash,zsh,破折号),export也会显示该值。例如,使用bash:

$ export
export FOO2='as  df\
  asdk=fja:\
asd=fa\
asdf'
export FOO='sjfkasjfd  kjasdf:\
   asdkj=fkajdsf:\
       :askjfkajsf=asdfkj:\
   safdkj'
$ printenv | sed -n l
FOO2=as\tdf\$
  asdk=fja:\$
asd=fa\$
asdf$
FOO=sjfkasjfd  kjasdf:\$
   asdkj=fkajdsf:\$
\t:askjfkajsf=asdfkj:\$
   safdkj$

其他选项(例如,envprintenv没有选项)仅显示不带值的变量名,至少在我尝试过的linux和freebsd平台上不行。

管道到awk / sed / etc。或使用参数扩展技术(例如${foo%%=*})修剪列表是可以接受的,但是它必须使用可能跨越行且值中带有=空格的值(请参见上面的示例)。

特定于特定Shell实现的答案很有趣,但是我主要是在寻找在各个实现之间都兼容的东西。


2
如果要解析某些内容,请使用export -pPOSIX指定的输出来生成也适用于Shell中输入的输出。
Kusalananda

我不需要任何输入到外壳程序。我只想要环境变量的名称。因此,多余的杂物(例如,每行开头的“导出”一词)无论如何都必须删除。我为什么要为此使用export -p
胡安

1
您想使用它,export -p因为那样可以在您说过的所有POSIX Shell中为您提供一致的输出。
Kusalananda

我想要一个仅打印变量名的解决方案,这是跨shell的一致解决方案。 export -p不符合第一个要求-仅打印不带值的变量名。
胡安

如果您要解析某些内容,请使用的输出export -p。我不会编写该解析,因为在一般情况下,如果您有一个变量的值类似于,则还必须进行适当的引号解析hello\nexport var=value。其中的几个,这将使你在所有的POSIX外壳一致的输出其它的命令是env,但输出是很难解析,因为它缺乏export =位。
Kusalananda

Answers:


9

在awk中非常简单。

awk 'BEGIN{for(v in ENVIRON) print v}'

但是请注意,某些awk实现会添加自己的环境变量(例如GNU awk add AWKPATHAWKLIBPATHto ENVIRON)。

如果环境变量的名称包含换行符,则输出不明确,这是非常不寻常的,但在技术上是可行的。纯sh解决方案将很困难。最好的选择是从头开始,export -p但是很难以纯正的方式进行按摩。您可以使用sed按摩的输出export -p,然后使用eval来获取外壳,以删除其引用的内容。Bash和zsh打印非标准前缀。

report () { echo "${1%%=*}"; };
eval "$(export -p | sed "s/^export /report /;
                         s/^declare -x /report /;
                         s/typeset -x /report /")"

请注意,根据外壳程序的不同,export -p可能会或可能不会显示在外壳程序中名称无效的变量,如果无效,则可能会或可能不会正确引用名称。例如,破折号,mksh和zsh省略了名称包括换行符的变量,BusyBox破折号和ksh93将其原始打印,而bash则将其原始打印而没有它们的值。如果您需要防御不受信任的输入,请不要依赖纯粹的POSIX解决方案,并且绝对不要调用eval从的输出派生的任何东西export -p


我不确定带有多行值的sed(1)到底有多“容易”-我想看看。但是,感谢awk(1)方法。我认为这是迄今为止最方便的方法(尽管我认为这exit不是必需的)。
胡安

请注意,如果您得到FOO<newline>BAR,则不知道它是FOO<newline>BAR环境变量(export -p大多数外壳程序都不会显示,请参见env $'FOO\nBAR=test' awk 'BEGIN{for (v in ENVIRON) print v}')还是a FOOBAR环境变量。
斯特凡Chazelas

需要注意的是GNU awk自己的第设置环境变量(AWKPATHAWKLIBPATH我的系统上)
斯特凡Chazelas

@StéphaneChazelas-re:以var名称嵌入换行符-同意-很难用shell代码来防止这种情况。回复:AWKPATH和AWKLIBPATH污染,我也注意到阴险的插入。那是gnu awk,而不是bsd awk。
胡安

0

我喜欢简单的事情;这将适用于POSIX系统:

printenv | sed 's;=.*;;' | sort
HOME
HOSTNAME
PATH
PWD
SHLVL
TERM

5
export AAA=$'multi\nBBB=line'
roaima

@todd_dsm-对于具有跨越一行的值的环境变量,此操作将失败(例如,有时是TERMCAP-在screen(1)会话中,我看到了这一点,即IIRC)。因此,此答案不符合原始问题中描述的要求。我也喜欢简单,但这通常无法正常工作。
Juan

您在原始帖子中编辑的花絮对bash来说很有趣compgen -e。这对我的可移植脚本没有帮助(例如,当bash不可用时),但这很有趣。
Juan

只是好奇,为什么限制自己使用bourne(posix)shell?符合posix的标准很棒,但是您在追求这一目标时会损失很多功能。您可以携带并且不与posix兼容bash;它是GNU家族的一部分。
todd_dsm

dash在debian中使用时,使用上面的命令或修改后的命令可以获得相同的结果printenv | sed 's;*=.;;' | sort。我导出了变量yo并将其分配给您上面的第一个注释;它按预期打印,多行。不知道您正在经历什么,但不应将其截断。在外壳中运行命令;无论输出什么,它应该如何工作;期望不会被截断。然后,在TERMCAP / screen / iirc的上下文中;应该是一样的。如果输出不匹配,则可能是这些程序之一存在问题。
todd_dsm
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.