Parsing 使管道分隔文件中的字段为空

Parsing 使管道分隔文件中的字段为空,parsing,awk,pipe,delimited,Parsing,Awk,Pipe,Delimited,当数据字段中有管道时,我无法获得所需的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

当数据字段中有管道时,我无法获得所需的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"$

升级你的gawk版本是目前为止最好的方法,因为你错过了一些bug修复和自gawk 3.1.7 10多年前问世以来引入的大量非常有用的功能(我们目前使用的是gawk版本5.1!)但是,如果出于某种原因您无法做到这一点,那么-如果您没有在每个UNIX设备上的任何shell中使用任何awk的
FPAT
,您可以这样做:

$ 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
}

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

$ 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 ">"
    }
}
$cat tst.awk
开始{OFS=“|”}
{
原价=$0
$0=i=“”
while((orig!=“”)和&match(orig,/[^ |]*|(“[^”]*”+/)){
$(++i)=子字符串(起始、起始、长度)
orig=substr(orig,RSTART+RLENGTH+1)
}
打印NF“”

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

$ 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'BEGIN{OFS=FS=“\”“}{for(i=2;iLooks to be bug in the GNU awk version your have with use FPAT.根据此评论-,建议将您的gawk升级到4.2+,如果您使用的是FPATIt不是bug,FPAT只是在gawk 4.0之前才被引入,OP在gawk 3.1.7上(已经过时10年了!)@埃德蒙顿:哎呀!我不知道。无论如何,升级到后一个版本是OPS的一个选择。谢谢你回答这个问题。而不是创建(.awk脚本)-是否有任何其他方法可以获得所需的结果,或者我们是否可以有其他方法来解决此问题。我不确定你在问什么,但如果是如何执行awk脚本而不将其存储在一个文件中,该文件只是
awk'script'文件
而不是
awk-f tst.awk文件
。请参阅awk手册页,然后尝试
awk'BEGIN{}打印“你好,世界”}“
如果你不确定我的意思。我明白了。但我的问题是,有没有捷径可以获取o/pYes、更新你的gawk版本和使用FPAT。否则,我想我们会发现你是否得到了更短的答案。@AbdulWahabKhan,请停止从多个论坛中提取答案-已经提出了类似/相同的观点/意见,并找到了解决方案。”已提供。OP表示,无论他们处于何种环境,都不允许他们在脚本中使用反斜杠(
我使用的工具不允许使用字符(“-backslash”)
),因此可能需要调整或2。顺便说一句,
gsub()的第一个参数
是一个regexp,而不是一个字符串,因此如果使用regexp分隔符,则不需要在转义(
gsub(/\\\124;/…
)上加倍
$ 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 '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"