【问题标题】:Nullify fields in pipe delimited file取消管道分隔文件中的字段
【发布时间】:2020-11-30 03:49:19
【问题描述】:

当数据字段中有管道时,我无法获得所需的 o/p。

If the i/p is 
SAmple file is tst
hdr1|"hdr2|tst"|"hdr3|tst|tst"|hdr4|"hdr5|tst|tst"
lbl1|"lbl2|tst"|"lbl3|tst|tst"|lbl4|"lbl5|tst|tst"

I tried with this cmd but dont get the expected o/p - cut -f2,3 -d"|" tst

The expected o/p is 
"hdr2|tst"|"hdr3|tst|tst"
"lbl2|tst"|"lbl3|tst|tst"

有没有一种简单的方法可以破解这个 o/p...不想使用 sed bcoz 正在使用的工具不允许字符(“”-反斜杠)。我的意思是将此命令嵌入其中一个工具中 我也在使用旧版本的 gawk -

so this cmd doesnt give te desired o/p
gawk -v FPAT='[^|]*|("[^"]*")+' '{print $2, $3}' OFS="|"

Output of gawk --version
GNU Awk 3.1.7

Output of cat -vet tst

hdr1|"hdr2|tst"|"hdr3|tst|tst"|hdr4|"hdr5|tst|tst"$
lbl1|"lbl2|tst"|"lbl3|tst|tst"|lbl4|"lbl5|tst|tst"$

【问题讨论】:

  • 看起来是您使用 FPAT 的 GNU awk 版本中的错误。根据此评论 - stackoverflow.com/questions/49031764/…,如果您使用 FPAT,建议将您的 gawk 升级到 4.2+
  • 这不是一个错误,直到 gawk 4.0 才引入 FPAT,并且 OP 在 gawk 3.1.7 上(已经过时了大约 10 年!)
  • @EdMorton:哎呀!不知道。无论如何,升级到后一个版本是 OP 的一种选择

标签: parsing awk pipe delimited


【解决方案1】:

升级您的 gawk 版本是迄今为止最好的方法,因为您缺少一些错误修复以及自 10 多年前 gawk 3.1.7 推出以来引入的大量非常有用的功能(我们目前使用的是 gawk 5.1 版) !)但是如果由于某种原因你不能这样做 - 如果你没有 FPAT 在每个 UNIX 机器上的任何 shell 中使用任何 awk,你可以这样做:

$ cat tst.awk
BEGIN { OFS="|" }
{
    orig = $0
    $0 = i = ""
    while ( (orig != "") && match(orig,/[^|]*|("[^"]*")+/) ) {
        $(++i) = substr(orig,RSTART,RLENGTH)
        orig = substr(orig,RSTART+RLENGTH+1)
    }
    print $2, $3
}

.

$ awk -f tst.awk file
"hdr2|tst"|"hdr3|tst|tst"
"lbl2|tst"|"lbl3|tst|tst"

只是为了验证它是否正确识别了所有字段:

$ cat tst.awk
BEGIN { OFS="|" }
{
    orig = $0
    $0 = i = ""
    while ( (orig != "") && match(orig,/[^|]*|("[^"]*")+/) ) {
        $(++i) = substr(orig,RSTART,RLENGTH)
        orig = substr(orig,RSTART+RLENGTH+1)
    }

    print NF " <" $0 ">"
    for (i=1; i<=NF; i++) {
        print "\t" i " <" $i ">"
    }
}

.

$ awk -f tst.awk file
5 <hdr1|"hdr2|tst"|"hdr3|tst|tst"|hdr4|"hdr5|tst|tst">
        1 <hdr1>
        2 <"hdr2|tst">
        3 <"hdr3|tst|tst">
        4 <hdr4>
        5 <"hdr5|tst|tst">
5 <lbl1|"lbl2|tst"|"lbl3|tst|tst"|lbl4|"lbl5|tst|tst">
        1 <lbl1>
        2 <"lbl2|tst">
        3 <"lbl3|tst|tst">
        4 <lbl4>
        5 <"lbl5|tst|tst">

【讨论】:

  • 感谢您回答这个问题。而不是创建(.awk 脚本) - 有没有其他方法可以获得所需的结果,或者我们可以有其他方法来解决这个问题。
  • 我不确定你在问什么,但如果它是如何执行 awk 脚本而不将其存储在一个只是 awk 'script' file 而不是 awk -f tst.awk file 的文件中。如果您不确定我的意思,请参阅 awk 手册页并尝试 awk 'BEGIN{print "Hello World"}'
  • 我知道了。但我的问题是,有没有捷径可以得到 o/p
  • 是的,更新您的 gawk 版本并使用 FPAT。否则我想我们会知道你是否得到任何简短的答案。
  • @AbdulWahabKhan,请停止从多个论坛中提取答案 - 类似/相同的点/cmets 已经提出并提供了解决方案。
【解决方案2】:

如果您没有嵌入双引号,您可以用另一个未使用的字符(我使用~)替换带引号的分隔符值,并在提取后切换回原始值。显然它要求在文本中不使用新的分隔符。

$ awk 'BEGIN{OFS=FS="\""} {for(i=2;i<NF;i+=2) gsub("\\|","~",$i)}1' file | 
  awk 'BEGIN{OFS=FS="|"}  {print $2,$3}'                                 | 
  sed 's/~/|/g' 

"hdr2|tst"|"hdr3|tst|tst"
"lbl2|tst"|"lbl3|tst|tst"

不确定它是否比单个 awk 脚本更简单。

这里的主要问题是文档格式设计。如果有嵌入的双引号或转义管道等,则需要另一个补丁。

【讨论】:

  • OP 说无论他们所处的环境不允许他们在脚本中使用反斜杠 (the tool that am using doesnt allow the charecter (""- backslash)),因此可能需要调整或 2。顺便说一句,gsub() 的第一个参数是一个正则表达式,而不是字符串,所以如果你使用正则表达式分隔符,那么你就不需要加倍转义(gsub(/\|/...
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2010-09-17
  • 1970-01-01
  • 2020-08-14
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-02-19
相关资源
最近更新 更多