我提出了一些解决方案,但我不喜欢它们。我想知道是否有更好的方法。我主要是在寻找简洁,不需要标志且可在大多数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工具可以处理我没有想到的用例?
答案 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
-n
和p
标志是标准标志,仅在正则表达式被认定为有效时,才指示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
转义序列。文本文件通过“命令替换”处理。 -s
至bash
告诉它以标准输入作为其脚本。