当列具有重复值

时间:2018-05-09 07:36:24

标签: linux awk

情景1

仅当第1列为CR且第3列与行/值重复时,我才需要进行以下更改。此输入文件可以包含列3中的100个重复行

第3列中的值为后缀,序列从a后跟CR开始 如果我们附加后缀直到a z与CR一样(aCR, bCR, cCRzCR),那么下一个后缀将是aaCR, abCR, acCR,依此类推第3列

输入文件

a||c
CR||2157237496
CR||2157237496
CR||2157237496
INV||2157237496
RNV||3457634589

输出文件

a||c
CR||2157237496aCR
CR||2157237496bCR
CR||2157237496cCR
INV||2157237496
RNV||3457634589

场景2

需要在单独的代码中执行此操作。以下是针对不同的文件。只有当第1列是DR并且第3列有重复的行/值时,我才需要在下面进行更改。第3列中的值为后缀,序列从a开始,第一个文档后跟DR除外。

如果我们添加了后缀,直到a z与DR一样(aDR, bDR, cDRzDR),那么下一个后缀将为aaDR, abDR, acDR,对于第3列< / p>

输入文件

a||c
DR||3770022521
DR||3770022521
DR||3770022521
INV||9876543738

输出文件

a||c
DR||3770022521
DR||3770022521aDR
DR||3770022521bDR
INV||9876543738

我尝试了下面的代码,它为方案2提供输出,但无法将序列号附加到column3。我只能后缀a,这是静态的。 这里需要考虑第1列等于场景1的CR和场景2的DR(我无法做到)

awk -F"|" -v OFS="|" '{if(++a[$3]>1)$3=$3"a"}1' d1.txt

代码输出:

a||c
CR||2157237496
CR||2157237496a
CR||2157237496a
INV||2157237496a
RNV||3457634589

我需要分别实施方案1和2

2 个答案:

答案 0 :(得分:2)

我可以提供一种方法来解决第一个场景,您可以使用它来扩展第二个场景。它涉及对文件进行两次解析,但仅限于第二次传递的选定列。如果能够一次性完成,我会兴高采烈地删除答案。

步骤

  • 创建函数,根据需要使用带有ASCII代码的a-zsprintf()生成字母字符
  • 在第一遍中,为第一列中的值创建包含第三列的值的哈希映射,为CR
  • 再次在这些列的第二次传递中,修改$3以生成所需的模式。

脚本应如下所示。将其命名为script.awk

#!/usr/bin/env awk


function generateAlphabets() {
    idx = 0
    for(i=97;i<123;i++ ) {
        letters[idx++]=sprintf("%c",i)
    }
}

BEGIN {
    generateAlphabets()
    FS=OFS="|"
    counter=0
}

$1 == "CR" {
    map[$1""$3]
}

FNR == NR { next }

($1""$3 in map) {
    $3 = $3""letters[counter++]"CR"
}1

运行以下脚本
awk -f script.awk file file

您可以通过awk变量传递CRDR来扩展第二种方案,并在适用的地方将字符串替换为代码中的变量

答案 1 :(得分:2)

编辑:当@Inian抓住我的手并重新阅读OP给我时,我编辑了脚本以实际支持重复。首先,测试数据要好一些:

a||c
CR||2157237496
CR||2157237497
CR||2157237496
CR||2157237497
INV||2157237496
RNV||3457634589

方案1的awk:

$ awk '
BEGIN {
    FS=OFS="|"                       # field delimiters
    ab="zabcdefghijklmnopqrstuvwxy"  # mod safe alphabet
    d=26                             # size of alphabet
}
function i2ab(n,    b) {             # b is local var
    while(n>=1) {
        p=n%d                        # this is the letter position
        n=n/d                        # n for the next round
        n-=(n==int(n))               # fix for n%d==0 else 26 -> az, not z
        b=substr(ab,p+1,1) b         # prepend the next letter to buffer
    }
    return b                         # return buffer
} 
$1=="CR" {                           # for DR change CR to DR and ++a[$3] to a[$3]++ below
    $3=$3 i2ab(++a[$3]) $1           # increment c and map it to a string
}1' file                             # output
a||c
CR||2157237496aCR
CR||2157237497aCR
CR||2157237496bCR
CR||2157237497bCR
INV||2157237496
RNV||3457634589

请参阅注释以更改它以使用方案2。

函数i2ab在26之后也提供字母组合:

$ awk '
BEGIN {
    ab="zabcdefghijklmnopqrstuvwxy"
    d=26
    print i2ab(27)                   # I AM HERE 26 -> z, 27 ->aa
}                                           
function i2ab(n,    b) {                    #
    while(n>=1) {                           #
        p=n%d                               #
        n=n/d                               #
        n-=(n==int(n))                      #
        b=substr(ab,p+1,1) b              #####
    }                                      ###
    return b                                #
}'
aa                                    # I DID THIS