有没有一种可移植且简洁的方法可以从脚本中解析环境变量?

时间:2019-08-13 06:18:47

标签: perl awk sed grep

我提出了一些解决方案,但我不喜欢它们。我想知道是否有更好的方法。我主要是在寻找简洁,不需要标志且可在大多数Unix系统上使用的东西。 我也不完全确定以下哪一项是最可移植的。据我所知,唯一的不是gawk解决方案。


示例文件

我想解析BAR变量的值

# a comment
FOO="ENV_FOO"
BAR="ENV_BAR"
textfile="# a comment\nFOO=\"ENV_FOO\"\nBAR=\"ENV_BAR\""

# awk: split on "=" delimiter 
echo $textfile | awk -F "=" '/^BAR=/ { gsub(/"/,"",$2); print $2 }'

# awk: replace beginning of string with empty string; handle quotes with tr
echo $textfile | awk '/^BAR=/ { gsub(/^.*BAR=/, ""); print }' | tr -d '"'

# gawk: most straight-forward to me but not portable or DRY
echo $textfile | gawk '/^BAR=/ { print gensub(/^.*BAR="(.*)"$/, "\\1", "g") }'

# grep + sed
echo $textfile | grep ^BAR= | sed -E 's#^.*"(.*)"$#\1#'

# sed only
echo $textfile | sed -nE 's#^BAR="(.*)"$#\1#p'

# perl: maybe I just need to work on remembering these flags as this is succint
echo $textfile | perl -alE 'print $1 if /^BAR="(.*)"$/'

它们中的每一个都以其自己的方式很简单,但是许多都需要记住一些特殊的标志,这些标志必须包含在内才能正常工作。是否有另一个标准的unix工具可以处理我没有想到的用例?

5 个答案:

答案 0 :(得分:4)

perl -wnE'/^BAR="([^"]+)/ and say $1' file

perl -wlne'/^BAR="([^"]+)/ and print $1' file

因此请不要启用feature的所有 -E个。 -w启用警告,可以将其放在此处。


至于“ 记住这些标志”,基础知识非常合理

  • -e告诉解释器 E 将代码之间的引号括起来;这就是使它成为命令行上的“单一程序”或程序的原因。它必须在程序前加引号

  • -n打开一个文件,并为所有提交的文件一次向程序输入一行;这是使用文件时想要的。 -p执行相同的操作, 打印每行

就是这样,满足大多数常见需求。因此,perl -ne'...' file在文件的每一行中都在''中运行代码(以及其他开关的影响);我总是扔进-w

当然还有许多其他开关,如in perlrun所述,是为了更具体的方便或使用。一些杰出的人

  • -M将模块加载为-MModuleName。也可以指定要导入的函数,请参阅文档

  • -0777一次读取整个文件(“ slurp”)。这将设置输入记录分隔符($/),以便将整个文件视为一个“行”-因此我们仍然需要-n

  • -C,后跟Unicode功能的编号/列表,例如-CASD

  • 上面使用的
  • -l,用于处理 L 个底端,在输入端去除它们并追加输出

通常,该行(处于slurp模式的文件)进入$_ variable,这是Perl中的全面默认值。

要查看与Perl在给定的单行代码上运行的代码非常接近的代码,请在交换机上添加-MO=Deparse,该交换机使用B::Deparse编译器后端(通过O模块)

答案 1 :(得分:3)

您可以获取文件:

source /path/to/the/textfile
echo "$BAR"

答案 2 :(得分:2)

您可以使用sed版本的命令,该版本保证与POSIX兼容,如下所示:

sed -n 's/^BAR="\([^"]*\).*$/\1/p' file

-np标志是标准标志,仅在正则表达式被认定为有效时,才指示sed打印捕获的模式\1

您还可以如下在OP中使用gawk变体中定义的正则表达式。

sed -n 's/^BAR="\(.*\)"$/\1/p'

P.S。请注意,除非您添加有关在哪种最小系统上运行(可能仅需要POSIX)的更多详细信息,否则对此没有明确的答案。您也可以分析每个建议,然后选择最能解决用例的建议。

答案 3 :(得分:0)

awk

echo $textfile | awk -F\" '/^BAR=/{print $2}'

您可以将"用作字段分隔符。 这样,相关行中的第二个awk值将返回,将成为所需的变量值。

答案 4 :(得分:0)

这可能太可爱了,但是您可以使用sed将文本文件转换为perl程序,将env分配转换为哈希分配,并为结果附加一个perl打印语句:

$ sed 's/\(.*\)=/$e{\1}=/;s/$/;/;$aprint $e{BAR}' textfile
# a comment;
$e{FOO}="ENV_FOO";
$e{BAR}="ENV_BAR";
print $e{BAR}

当您将其简单地传递到perl中时,它会为您提供所需的结果:

$ sed 's/\(.*\)=/$e{\1}=/;s/$/;/;$aprint $e{BAR}' textfile|perl
ENV_BAR

除了过于可爱之外,这当然还带来了效率低下的额外负担-对于其他解决方案,两次通过而不是一次。

从好的方面来说,sed和perl可能是程序的可移植性,并且没有任何“标志”,因此...取舍。

更新:我想到,因为无论如何环境变量/语法都是为shell设计的,因此即使不“轻巧”地使用它,也可以直接将相同的想法用于shell,而无需进行任何语法按摩。这是bash:

$ IFS=; echo -e "$(<textfile)\necho \$BAR"|bash -s
ENV_BAR

说明:将IFS设置为null会停止“单词拆分”,否则将从文本文件输出中删除换行符。 -e使echo识别\n转义序列。文本文件通过“命令替换”处理。 -sbash告诉它以标准输入作为其脚本。