我有 file1.txt:
1|2022-09-29|03:15:00
2|2022-09-29|10:50:00
3|2022-09-29|07:15:00
和文件2.txt:
1|red|info 1
2|blue
3|yellow|info 2
我想将这些文件连接到一个 file3.txt 中,使其看起来像这样:
red|2022-09-29|03:15:00|info 1
blue|2022-09-29|10:50:00|
yellow|2022-09-29|07:15:00|info 2
所以我尝试输入一个脚本:
#!/bin/bash
awk -F'|' 'NR==FNR {a[$1]=$2;next} ($1 in a) {a[$1]=$2"|"a[$1]"|"a[$3]"|"$3; print a[$1]}' file1.txt file2.txt > file3.txt
但我的输出看起来像这样:
red|2022-09-29||info 1
blue|2022-09-29||
yellow|2022-09-29||info 2
正如你所看到的 file1.txt 的第三部分丢失了,我不明白为什么。如果您向我指出我做错了什么,我将不胜感激。
答案1
答案相当简单:您用来a[$3]
引用 的第三列file1
。然而
- 您使用数组
a
来存储 的第二列file1
,而不是第三列,并且 - 您只使用第一列(数字)作为“键”,因此尝试访问
a["info 1"]
(就像您a[$3]
在处理的第一行中所做的那样file2
)将不会返回任何内容。
下面的程序可以做到:
awk 'BEGIN{FS=OFS="|"} NR==FNR{d[$1]=$2;t[$1]=$3;next} ($1 in d) {print $2,d[$1],t[$1],$3}' file1.txt file2.txt > file3.txt
这设置|
为输入和输出的字段分隔符。
- 处理时
file1.txt
,它将日期存储在数组中d
,将时间存储在数组中t
,以第一列(数字)作为键。 - 处理 时
file2.txt
,它打印第 2 列、与第 1 列对应的日期和时间,然后打印第 3 列中的“info”值,用作|
输出分隔符。
答案2
您可以信赖join
:
join -t\| -j 1 -o 1.2,2.2,2.3,1.3 file2 file1
其中 format( -o
) 定义为FILE.FIELD
,因此只需选择从哪个输入文件中获取哪个字段-t
即可定义字段定界符并-j
用于定义任一文件中用于匹配的公共字段。
请注意,可能需要排序:
join -t\| -j 1 -o 1.2,2.2,2.3,1.3 <(sort file2) <(sort file1)
答案3
awk 'BEGIN{FS=OFS="|"} NR==FNR {a[$1]=$2 OFS $3;next} ($1 in a) {print $2,a[$1],$3}' file1.txt file2.txt > file3.txt
出于可移植性的目的,我从 开始BEGIN{FS=OFS="|"}
,它允许您选择字段分隔符和输出字段分隔符。
然后,当您在第一个文件中时,NR==FNR
您注册了用输出字段分隔符分隔的第二个和第三个字段{a[$1]=$2 OFS $3;next}
,并且您到达了下一行,但尚未打印任何内容。在您的脚本中,您从未注册第三个字段,这就是您无法输出它的原因。
当您到达第二个文件时,您的NR
和FNR
会有所不同,并检查您的第一个字段是否在您的 array 中($1 in a)
。我没有注册第二个字段、数组和第三个字段然后打印它,而是立即打印它{print $2,a[$1],$3}
。
答案4
假设两个输入文件中的数据是“简单”CSV 记录,不包含包含嵌入分隔符或换行符的字段,这些|
字符是分隔符,并且文件逐行匹配,如问题中所示:
这两个文件可以并排呈现给awk
using paste
,并且awk
可以用于按照我们需要的顺序挑选出我们想要的字段:
paste -d '|' file1 file2 |
awk -F '|' 'BEGIN { OFS=FS } { print $5, $2, $3, $6 }' >file3
file3
给出问题中的数据的结果:
red|2022-09-29|03:15:00|info 1
blue|2022-09-29|10:50:00|
yellow|2022-09-29|07:15:00|info 2