使用 Perl 的列过滤器表达式的正确联机程序是什么?

What is the correct onliner for a column filter expression using Perl?

我尝试从 Linux 下的配置文件中过滤表达式,在管道中混合 bash 命令行工具和 Perl 命令。

我有一个配置文件(参见配置部分),可以使用 `

过滤相关行
grep PG.DATABASE database.conf | \
sed -r -e 's/^\s*//;s/\s+/ /'  | \
cut -d ' ' -f2 | \
sort

并得到预期的结果:

DB.GRM.CON.LOCAL.V01
DB.GRM.CON.LOCAL.V02
DB.GRM.CON.LOCAL.V03

现在我想切换到 Perl

grep PG.DATABASE database.conf | \
perl -lpe 's/^\s*//; @m = split /\s+/; print $m[1]'  

但是我得到了重复输入行的奇怪结果。

DB.GRM.CON.LOCAL.V01
PG.DATABASE: DB.GRM.CON.LOCAL.V01 BEGIN
DB.GRM.CON.LOCAL.V02
PG.DATABASE: DB.GRM.CON.LOCAL.V02 BEGIN
DB.GRM.CON.LOCAL.V03
PG.DATABASE: DB.GRM.CON.LOCAL.V03 BEGIN

问题

为什么会出现重复?使用命令行工具获得的结果是否正确?

配置文件

PG.CONFIG: DEFAULT BEGIN

   # Green Rebel Database via PG.SERVICE ------------------------
   PG.DATABASE: DB.GRM.CON.LOCAL.V01 BEGIN
     SERVICE:     'LOC-GRM-V0'
   END.DB.GRM.CON.LOCAL.V01

   # Green Rebel Database via DBI Driver ------------------------
   PG.DATABASE: DB.GRM.CON.LOCAL.V02 BEGIN
     DBI.PG: "dbi:Pg:dbname=grm;host=localhost;port=5432"
     AUTO.COMMIT: FALSE
     RAISE.ERROR: TRUE
     PRINT.ERROR: FALSE
   END.DB.GRM.CON.LOCAL.V02

   # Green Rebel Database via Host, Db, User, Pass --------------
   PG.DATABASE: DB.GRM.CON.LOCAL.V03 BEGIN
     SERVER:     'localhost'
     PORT:        5432
     DATABASE:    'grm'
     USER:        ${/SYSTEM/USER}
     SSL.MODE:    allow
     AUTO.COMMIT: FALSE
     RAISE.ERROR: TRUE
     PRINT.ERROR: FALSE
   END.DB.GRM.CON.LOCAL.V03
END.DEFAULT

我建议将 -p 选项(使其自动打印每一行)更改为 -n。您也可以跳过 grep,让 perl 执行:

perl -lne 'if(/PG\.DATABASE/) {chomp; s/^\s*//; @m = split /\s+/; print $m[1]}' database.conf

简化可以是:

perl -lne 'print  if(/PG\.DATABASE:\s(\S+)/)'  database.conf

您还可以让 perl 自动拆分成列,这可能是 在 perl 中过滤 的正确方法

perl -lane 'print $F[1] if $F[0] eq "PG.DATABASE:"' database.conf
DB.GRM.CON.LOCAL.V01
DB.GRM.CON.LOCAL.V02
DB.GRM.CON.LOCAL.V03

但是你的格式并不是真正面向列的,所以我会像其他答案一样使用正则表达式捕获解决方案:

perl -lne 'print  if(/^\s*PG\.DATABASE:\s*(\S+)/)' database.conf

我会做:

perl -nE 'say  if /^\s+PG\.DATABASE:\s+(\S+)/' file

这在 GNU grep 中也有效:

grep -oP '^\s+PG\.DATABASE:\s+\K\S+' file

和 GNU sed:

sed -nE 's/^\s+PG\.DATABASE:\s+(\S+).*//p' file

或POSIX sed:

sed -nE 's/^[[:blank:]]*PG\.DATABASE:[[:blank:]]*([^[:blank:]]*).*//p' file