在使用该行的一部分索引到 file2 并查找值后,如何将值附加到 file1 中的每一行?
How can I append values to each line in file1 after using part of that line to index into file2 and lookup the value?
我基本上有以下2个文件:
$ cat file1.txt
AB,12 34 56,2.4,256,,
CD,23 45 67,10.8,257,,
EF,34 56 78,0.6,258,,
GH,45 67 89,58.3,259,,
...
$ cat file2.txt
AB,12 34 56,2.4,36
XY,56 99 11,3.6,15
ZQ,12 36 89,5.9,0
EF,34 56 78,0.6,99
GH,45 67 89,58.3,79
...
并且对于 file1.txt 中的每一行,我想将前 3 个字段用作 file2.txt 中的索引,获取相应的最后一个字段,并将其放入 file1.txt 像这样:
cat newfile.txt
AB,12 34 56,2.4,256,36,
CD,23 45 67,10.8,257,,
EF,34 56 78,0.6,258,99,
GH,45 67 89,58.3,259,79,
不能保证 file1 中的每一行都会出现在 file2 中,反之亦然,对于这种情况,上面 newfile.txt 中显示的空字段是可以的。
在我的第一次尝试中,我在 while read
循环中读取 file1 中的每一行,然后在 file2 中查找适当的行,它起作用了,但速度太慢了。 file1 和 file2 各有几十万行。
有什么方法可以使用 sed 将 file1 中每一行的前 3 个字段用作 file2 的索引,查找我需要的值,并将其附加到 file1 中的该行?并且不逐行读取文件 1 就这样做吗?
感谢任何帮助。
使用 join
和 sed
(用于某些预处理和 post 处理),并假设 |
字符未出现在两个文件中
join -a1 -t'|' \
<(sort file1.txt | sed 's/,/|/3') \
<(sort file2.txt | sed 's/,/|/3') |
sed 's/,|//; s/|/,/; s/[^,]$/&,/' > newfile.txt
(使用问题中给出的输入进行测试)
可以使用关联数组 bash
简单地完成,但我怀疑它是否有效。例如:
#!/bin/bash
declare -A tail
while IFS= read -r line; do
if [[ $line =~ ([^,]*,){3} ]]; then
tail[${BASH_REMATCH[0]}]=${line#"${BASH_REMATCH[0]}"}
fi
done < file2.txt
while IFS= read -r line; do
if [[ $line =~ ([^,]*,){3} ]] && [[ -n ${tail[${BASH_REMATCH[0]}]} ]]; then
printf '%s%s\n' "${line%?}" "${tail[${BASH_REMATCH[0]}]},"
else
printf '%s\n' "$line"
fi
done < file1.txt > newfile.txt
使用 awk:
awk -F, 'FNR==NR { map[","","]=;next } { print ","","","","map[","","]"," }' file2.txt file1.txt
Process file1.txt first (FNR==NR) 创建一个数组映射,以第一个、第二个和第三个逗号分隔的字段为索引,第4个字段为值。然后对于第二个文件,打印第一个、第二个、第三个和第四个字段以及第一个索引的映射数组的内容,以逗号分隔。
这将在每个 Unix 机器上使用任何 shell 中的任何 awk 非常有效地工作,并且不依赖于输入中不存在的任何字符:
$ awk '
BEGIN { FS=OFS="," }
{ key = FS FS }
NR==FNR { map[key] = ; next }
{ = map[key] }
1' file2 file1
AB,12 34 56,2.4,256,36,
CD,23 45 67,10.8,257,,
EF,34 56 78,0.6,258,99,
GH,45 67 89,58.3,259,79,
我基本上有以下2个文件:
$ cat file1.txt
AB,12 34 56,2.4,256,,
CD,23 45 67,10.8,257,,
EF,34 56 78,0.6,258,,
GH,45 67 89,58.3,259,,
...
$ cat file2.txt
AB,12 34 56,2.4,36
XY,56 99 11,3.6,15
ZQ,12 36 89,5.9,0
EF,34 56 78,0.6,99
GH,45 67 89,58.3,79
...
并且对于 file1.txt 中的每一行,我想将前 3 个字段用作 file2.txt 中的索引,获取相应的最后一个字段,并将其放入 file1.txt 像这样:
cat newfile.txt
AB,12 34 56,2.4,256,36,
CD,23 45 67,10.8,257,,
EF,34 56 78,0.6,258,99,
GH,45 67 89,58.3,259,79,
不能保证 file1 中的每一行都会出现在 file2 中,反之亦然,对于这种情况,上面 newfile.txt 中显示的空字段是可以的。
在我的第一次尝试中,我在 while read
循环中读取 file1 中的每一行,然后在 file2 中查找适当的行,它起作用了,但速度太慢了。 file1 和 file2 各有几十万行。
有什么方法可以使用 sed 将 file1 中每一行的前 3 个字段用作 file2 的索引,查找我需要的值,并将其附加到 file1 中的该行?并且不逐行读取文件 1 就这样做吗?
感谢任何帮助。
使用 join
和 sed
(用于某些预处理和 post 处理),并假设 |
字符未出现在两个文件中
join -a1 -t'|' \
<(sort file1.txt | sed 's/,/|/3') \
<(sort file2.txt | sed 's/,/|/3') |
sed 's/,|//; s/|/,/; s/[^,]$/&,/' > newfile.txt
(使用问题中给出的输入进行测试)
可以使用关联数组 bash
简单地完成,但我怀疑它是否有效。例如:
#!/bin/bash
declare -A tail
while IFS= read -r line; do
if [[ $line =~ ([^,]*,){3} ]]; then
tail[${BASH_REMATCH[0]}]=${line#"${BASH_REMATCH[0]}"}
fi
done < file2.txt
while IFS= read -r line; do
if [[ $line =~ ([^,]*,){3} ]] && [[ -n ${tail[${BASH_REMATCH[0]}]} ]]; then
printf '%s%s\n' "${line%?}" "${tail[${BASH_REMATCH[0]}]},"
else
printf '%s\n' "$line"
fi
done < file1.txt > newfile.txt
使用 awk:
awk -F, 'FNR==NR { map[","","]=;next } { print ","","","","map[","","]"," }' file2.txt file1.txt
Process file1.txt first (FNR==NR) 创建一个数组映射,以第一个、第二个和第三个逗号分隔的字段为索引,第4个字段为值。然后对于第二个文件,打印第一个、第二个、第三个和第四个字段以及第一个索引的映射数组的内容,以逗号分隔。
这将在每个 Unix 机器上使用任何 shell 中的任何 awk 非常有效地工作,并且不依赖于输入中不存在的任何字符:
$ awk '
BEGIN { FS=OFS="," }
{ key = FS FS }
NR==FNR { map[key] = ; next }
{ = map[key] }
1' file2 file1
AB,12 34 56,2.4,256,36,
CD,23 45 67,10.8,257,,
EF,34 56 78,0.6,258,99,
GH,45 67 89,58.3,259,79,