awk 脚本,用于在列具有重复值时将后缀附加到列

  • 本文关键字:后缀 脚本 用于 awk linux awk
  • 更新时间 :
  • 英文 :


>场景 1

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

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

输入文件

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除外。

如果我们用 DR like(aDR, bDR, cDR直到zDR(附加了后缀直到 a 到z,那么下一个后缀将在第 3 列中aaDR, abDR, acDR和依此类推

输入文件

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

输出文件

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

我尝试了下面的代码,它为我提供了场景 2 的输出,但无法将序列号附加到第 3 列。我只能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

编辑:当@Inian握住我的手并重新向我朗读OP时,我编辑了脚本以实际支持重复项。首先,更好的测试数据:

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

场景 1 的尴尬:

$ 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

我可以提供一种解决第一种情况的方法,您可以使用该方法进行扩展以使第二种情况也起作用。它涉及文件的两次解析,但仅在第二次传递时对所选列进行分析。如果答案能够一次性完成,我将兴高采烈地删除答案。

步骤

  • 创建函数以根据需要使用带有 ASCII 代码的sprintf()a-z生成字母字符
  • 在第一次传递时,为第三列中包含的值创建一个哈希映射,将第一列中的值作为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,并在适用的情况下将字符串替换为代码中的变量

最新更新