Awk 删除记录中重复的字段

Awk 删除记录中重复的字段,awk,Awk,在此处输入code我想删除每条记录中键的重复实例(前两个字段)。在我看来,复制品实际上是反向的 如此给定 a b b a stuff1 b a stuff2 stuff3 b a 其中每个空格都是一个选项卡 我想: a b stuff1 stuff2 stuff3 我想这样就行了: awk 'BEGIN {FS=OFS="\t"} {gsub($2 "\t" $1,"")} 1' file 欢迎使用其他解决方案,但我特别感兴趣的是为什么这不起作用 (我用一个动态reg

在此处输入code
我想删除每条记录中键的重复实例(前两个字段)。在我看来,复制品实际上是反向的

如此给定

a b b a stuff1 b a stuff2 stuff3 b a
其中每个空格都是一个选项卡

我想:

a b stuff1 stuff2 stuff3
我想这样就行了:

awk 'BEGIN {FS=OFS="\t"} 
     {gsub($2 "\t" $1,"")}
     1' file
欢迎使用其他解决方案,但我特别感兴趣的是为什么这不起作用
(我用一个动态regexp和
gensub
btw进行了尝试)

根据前面的问题,我知道我可能/将以重复选项卡结束,并将在
awk
之外处理该问题

编辑

到目前为止,解决方案不起作用,所以这里是真实的数据。对于^read,读取制表符

1874    ^Passage de Venus^  <DIRECTORS> ^Passage de Venus^  1874^   Janssen, P.J.C.^    <keywords>^ Passage de Venus^   1874^   astronomy^  astrophotography^   <genres>^   Short
1874^金星之路^金星之路^ 1874^杨森,P.J.C.^金星之路^ 1874^天文学^天体摄影^简称
我想要的是

1874^   Passage de Venus^   <DIRECTORS>^    Janssen, P.J.C.^    <keywords>^ astronomy^  astrophotography^   <genres>^   Short
1874^维纳斯之路^杨森,P.J.C.^天文学^天体摄影^简称

我能想到的唯一问题是输入文件没有用制表符分隔

测试

$ echo "a b b a stuff1 b a stuff2 stuff3 b a" | awk  '{gsub($2" "$1,"")}1'
a b  stuff1  stuff2 stuff3

您的尝试很好,您可能在空格/制表符方面遇到了一些问题。此外,您可能希望使用
FS
使其更易更改:

awk 'BEGIN {FS=OFS="\t"} {gsub($2 FS $1, "")}1' file
             |____________________^
因此,如果您注意到字段分隔符是另一个,只需在
BEGIN
块中更改它,它就会正常工作

试验 你可以试试这个

awk '{gsub($2 "[[:space:]]+" $1, "")}1' file
如果这样做有效并且使用
“\t”
不起作用,那么您可能没有使用选项卡

再次检查没有错误,很可能您的文件中的选项卡旁边有空间

试一试

虽然这个答案纯粹是为了排除gsub不起作用的原因,但我已决定在评论中添加此附录,以解决Eds问题

这将停止匹配除
$2
之外的单词,然后再匹配
$1
,并且还应清理格式混乱

awk 'BEGIN{FS=" *\t *"}{$0=gensub("("FS")" $2 FS $1 "("FS")","\\1","g")}1' file
例子 即使使用metachars,它也应该更加健壮

awk -F' *\t *' '{x=y;for(i=1;i<=NF;i++)(i>2&&$i==$2&&$(i+1)==$1&&i++)||x=x?x"\t"$i:$i;$0=x}1' file
awk-F'*\t*'{x=y;对于(i=1;i2&&$i==$2&&$(i+1)=$1&&i++)| x=x?x“\t”$i:$i;$0=x}1”文件

这是您真正需要的解决方案,因为它对完整字段进行字符串比较,因此当字段包含重元字符或字段以与$1/$2相同的值开始或结束时,不会出现错误匹配:

awk -F' *\t *' -v OFS='\t' '{
    rec = $1 OFS $2
    for (i=3; i<=NF; i++) {
        if ( ($i == $2) && ($(i+1) == $1) ) {
            i += 2
        }
        else {
            rec = rec OFS $i
        }
    }
    print rec
}
' file
awk-F'*\t*'-v OFS='\t''{
记录=1美元/2美元

对于(i=3;i请发布一些代码不起作用的记录我是否遗漏了什么?这应该不会有任何区别??FS是一个空格(或它设置为的任何内容)当这样使用时,使用制表符不会产生任何影响。是的,它不会产生任何影响。仍然不能处理实际数据。不能使用逗号,因为它出现在数据中。使用反勾号“。仍然不能处理我的数据。@IheOnwuka也许你可以尝试使用管道:
。另外,请确保没有任何尾随spaces。是的,我认为这样做可以奏效,但我真的想知道为什么更简单的解决方案不行。那么这是因为awk中有一个bug吗?@IheOnwuka再次检查,在第一个选项卡之前,您的示例中有空格,更新的答案应该是work@IheOnwuka数据中是否有与您的示例相同的
^
,因为其中一个字段和选项卡之间有空格?是的$2在字段分隔符之前有空格。我被迫插入它以使联接工作,但我忘记了它在那里。请注意,如果给定一些输入值,它将删除错误的文本,例如,在前两个字段中的任意一个字段中重新设置元字符,或者如果任意一个字段中的文本恰好是p将恰好相邻的其他字段中的文本进行部分匹配(例如,如果$1=
1234
和$2=
mal
,并且在文本中的某个地方您有
formal12345678
,则该字段将成为
for5678
)。不幸的是,您真的需要使用字符串匹配,而不是regexp匹配,并包含边界字符,以便为此类问题提供健壮的解决方案。如果您发现需要,请告诉我们。谢谢。这非常及时,因为我遇到了重元字符中止。但我不需要如此健壮的东西,因此我已经放弃了th$2!~/[[]/{gsub($2 FS$1,“”)}当我在文件中遇到更多的元字符时,我会修复它。这种方法几乎总是以沮丧和绝望告终,所以我不会这么做。如果您的字段可能包含不需要的RE元字符,那么只需编写脚本以使用字符串而不是REs。如果生成的脚本比您认为必须的更健壮,那就不是了一件可怕的事情。我不希望脚本比保证的更复杂。直到160k条记录进入文件,我才遇到这个问题,所以我可能会遇到130万条记录中的10个实例。对我来说,这只是一个try-catch解决方法,因为该语言缺少错误处理。好的,请确保每次都读取每一行输出您可以运行它,因为有时当脚本行为不受欢迎时,它不会产生任何类型的错误或警告消息,而只是默默地破坏输出。元字符失败实际上是偶然的,因为有些(不是全部)其中一个突出了已经渗透进来的异常。我的计划是标记它们,以便可以查看它们,但这还不够好,因为机制太粗糙(它捕获不会失败的东西)。基本上,我需要尝试捕获错误处理,可能需要将此问题转移到提供此功能的语言中。
 Input
 1234    mal     mal     1234    formal  12345678        blah

 Output
 1234    mal     formal  12345678        blah
awk -F' *\t *' '{x=y;for(i=1;i<=NF;i++)(i>2&&$i==$2&&$(i+1)==$1&&i++)||x=x?x"\t"$i:$i;$0=x}1' file
awk -F' *\t *' -v OFS='\t' '{
    rec = $1 OFS $2
    for (i=3; i<=NF; i++) {
        if ( ($i == $2) && ($(i+1) == $1) ) {
            i += 2
        }
        else {
            rec = rec OFS $i
        }
    }
    print rec
}
' file