perl 是否有一种相当可移植和简洁的方法来解析脚本中的环境变量?

nzrxty8p  于 2023-05-07  发布在  Perl
关注(0)|答案(5)|浏览(196)

我想出了一些解决办法,但我不喜欢它们。我在想有没有更好的办法。我主要是在寻找一些简洁的,不需要标志的东西,并且在大多数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工具可以处理这个我没有想到的用例?

yc0p9oo0

yc0p9oo01#

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

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

所以不启用 allfeature s with -E-w启用警告,可能可以将其放在这里。
至于“* 记住这些标志 *”的基本原理是非常合理的

  • -e告诉解释器将引号之间的内容E赋值为代码;这就是为什么它是一个“一行程序”,一个命令行上的程序。它必须正好在程序前面加上引号
  • -n打开一个文件,并为所有提交的文件一次提供一行;这是您在处理文件时所需要的。-p执行相同的操作,* 和 * 打印每一(处理过的)行

就这样,对于大多数普通的需求。因此perl -ne'...' file在文件的每一行上运行''中的代码(沿着其他开关的效果);我也总是在-w中抛出。
当然,还有很多其他的开关,在perlrun中有描述,用于更具体的方便或用途。几个突出的

  • -M加载一个模块,如-MModuleName。还可以指定要导入的函数,请参阅文档
  • -0777一次读取整个文件(“slurp”)。这将设置输入记录分隔符($/),以便将整个文件视为一个“行”--因此我们仍然需要-n
  • -C后跟Unicode功能的数字/列表,例如-CASD
  • 上面使用的-l,用于处理L行结尾,在输入端剥离它们并在输出端追加

通常这一行(slurp模式下的文件)会进入$_变量,这是Perl中的全面默认值。
要查看与Perl为给定的一行程序运行的代码非常接近的代码,请将-MO=Deparse添加到开关,它使用B::Deparse编译器后端(通过O模块)

tyu7yeag

tyu7yeag2#

您可以源文件:

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

6tdlim6h3#

您可以使用sed版本的命令,它保证符合POSIX,如下所示

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

-np标志是标准标志,用于指示sed仅在正则表达式被Assert为有效时才打印捕获的模式\1
您还可以在OP中使用在gawk变体中定义的正则表达式,如下所示。

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

P.S.请注意,这个问题没有明确的答案,除非您添加更多关于运行此程序的最小系统(可能只需要POSIX)的详细信息。您也可以分析每个建议,并选择最能解决您的用例的建议。

6kkfgxo0

6kkfgxo04#

awk

echo $textfile | awk -F\" '/^BAR=/{print $2}'
您可以使用"作为字段分隔符。这样,相关行中的第二个awk值将返回所需的变量值。

5m1hhzi4

5m1hhzi45#

这可能有点太可爱了,但是你可以将文本文件转换成一个perl程序,将env赋值转换成散列赋值,并为结果附加一个perl print语句,使用sed:

$ 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告诉它将标准输入作为脚本。

相关问题