我有 2 个文本文件
1.txt
AA;00000;
BB;11111;
GG;22222;
2.txt
KK;WW;55555;11111;
KK;FF;ZZ;11111;
KK;RR;YY;11111;
我尝试生成以下3.txt
输出:
AA;00000;
BB;11111;KK;WW;55555;KK;FF;ZZ;KK;RR;YY;
GG;22222;
删除重复字段后我应该有这个
AA;00000;
BB;11111;KK;WW;55555;FF;ZZ;RR;YY;
GG;22222;
简单来说:在两个以;
(FS=";") 分隔的文件中,如果文件 1 中的字段$n
出现在$m
文件 2 中的任何位置,且 m,n 不为 1,则将其附加$0(file2,m)
到$0(file1,n)
。必须避免出现重复的字段。
我会尝试勾勒出一个解决方案
awk -f script.awk 2.txt 1.txt
其中脚本如下:
BEGIN {
FS=";"
OFS=";"
}
NR==FNR {
allRecordsFile2[i++] = $0;
next;
}
{
for(r in allRecordsFile2)
{
split(allRecordsFile2[r],";",array)
for(f in array)
{
for($2 through $n of file1 currently processed)
{
if $n == f --> $0 = $0";"allRecordsFile2[r]
}
}
}
## cleanup duplicates
print $0
}
我仍然需要努力清除重复项,但可能可以通过拆分$0
并";"
使用计数数组来跟踪重复项来完成。
但是运行这个脚本后我返回语法错误
C:\Program Files (x86)\GnuWin32\bin>awk -f script.awk file2.txt file1.txt
awk: script.awk:17: for($2 through $n of filei currently processed)
awk: script.awk:17: “ syntax error
awk: script.awk:19: if $n == f --> $0 = $0";"allRecordsFile2[r]
awk: script.awk:19: “ syntax error
awk: script.awk:19: if $n == f --> $0 = $0";"allRecordsFile2[r]
awk: script.awk:19: “ syntax error
errcount:3
答案1
与其尝试顺序读取并基于FNR
/进行控制NR
,为什么不使用getline
读取2.txt
并拆分';'
,然后构建输出字符串(o
如下)来连接每行中唯一的组件?您可以做类似的事情:
awk '{
printf "%s", $0
}
/^BB/ {
o = ""
while (getline tmp < "2.txt") {
n = split (tmp,arr,";")
for (i=1; i<=n; i++)
if(!match($0,arr[i]) && !match(o,arr[i]))
o=o arr[i]";"
}
printf "%s", o
}
{
print ""
}
' 1.txt
使用/输出示例
1.txt
使用和中的示例数据2.txt
(您1.txt
再次错误命名),您将收到:
$ awk '{
> printf "%s", $0
> }
> /^BB/ {
> o = ""
> while (getline tmp < "2.txt") {
> n = split (tmp,arr,";")
> for (i=1; i<=n; i++)
> if(!match($0,arr[i]) && !match(o,arr[i]))
> o=o arr[i]";"
> }
> printf "%s", o
> }
> {
> print ""
> }
> ' 1.txt
AA;00000;
BB;11111;KK;WW;55555;FF;ZZ;RR;YY;
GG;22222;
这看上去就像你想要的。
作为以两个文件名作为参数的脚本
Windows 应该遵循相同的约定ARGV
。请注意,在脚本中运行时,不要在规则周围加上单引号awk
,例如
#!/usr/bin/awk -f
NR != FNR {
exit
}
{
printf "%s", $0
}
/^BB/ {
o = ""
while (getline tmp < ARGV[2]) {
n = split (tmp,arr,";")
for (i=1; i<=n; i++)
if(!match($0,arr[i]) && !match(o,arr[i]))
o=o arr[i]";"
}
printf "%s", o
}
{
print ""
}
(笔记:您需要将/usr/bin/awk
解释器更改为您拥有的任何解释器)
用法是,例如./test.awk 1.txt 2.txt
如果有帮助的话请告诉我。
答案2
使用关联数组的键可以方便地处理重复项。这需要 GNU awk 来实现多维数组
BEGIN { FS = OFS = ";" }
NR == FNR {
for (i=1; i<NF-1; i++)
f2[$(NF-1)][$i] = ++n
next
}
FNR == 1 {
# this joins all the 2nd-level indices
# the order of them is undefined.
for (x in f2) {
s = ""
for (y in f2[x])
s = s y OFS
a[x] = s
}
}
$(NF - 1) in a { $NF = a[$(NF-1)] }
1
然后
gawk -f script.awk {2,1}.txt
生产
AA;00000;
BB;11111;55555;WW;KK;RR;YY;FF;ZZ;
GG;22222;
我需要更多证据证明它对 URL“不起作用”:
$ cat 1.txt
AA;http://a.o/f/i.p?t=00000;
BB;http://a.o/f/i.p?t=11111;
GG;http://a.o/f/i.p?t=22222;
$ cat 2.txt
KK;WW;55555;http://a.o/f/i.p?t=11111;
KK;FF;ZZ;http://a.o/f/i.p?t=11111;
KK;RR;YY;http://a.o/f/i.p?t=11111;
$ gawk -f script.awk {2,1}.txt
AA;http://a.o/f/i.p?t=00000;
BB;http://a.o/f/i.p?t=11111;55555;WW;KK;RR;YY;FF;ZZ;
GG;http://a.o/f/i.p?t=22222;