如何在Unix中制作类似于Excel的vlookup函数的东西?
摘自办公室网站,查找表
VLOOKUP中的V代表垂直。当比较值位于要查找的数据左侧的列中时,请使用 VLOOKUP 而不是 HLOOKUP。
语法 VLOOKUP(lookup_value,table_array,col_index_num,range_lookup)
Lookup_value 要在表数组的第一列中搜索的值。 Lookup_value 可以是值或引用。如果lookup_value小于table_array第一列中的最小值,则VLOOKUP返回#N/A错误值。
Table_array 两列或多列数据。使用对范围或范围名称的引用。 table_array第一列的值是lookup_value搜索到的值。这些值可以是文本、数字或逻辑值。大写和小写文本是等效的。
Col_index_num table_array 中必须返回匹配值的列号。 col_index_num 为 1 返回 table_array 中第一列的值; col_index_num 为 2 返回 table_array 中第二列的值,依此类推。如果 col_index_num 是:
小于 1,VLOOKUP 返回#VALUE!误差值。大于 table_array 中的列数,VLOOKUP 返回#REF!误差值。
Range_lookup 一个逻辑值,指定您希望 VLOOKUP 查找精确匹配还是近似匹配:
文件1:
1GR_P1:001PI
:040VG_L1
:001PO_L3
1JPI_P1:001PO_L1
1JPI_P1:001PO_L2
文件2:
1JPI_P1:001PO_L1 1401UC
1JPI_P1:001PO_L2 1401UC
1HIK_P2:001ER 1402UC
1GR_P1:001PI 1402UC
输出文件3:
1GR_P1:001PI 1402UC
:040VG_L1 NA
:001PO_L3 NA
1JPI_P1:001PO_L1 1401UC
1JPI_P1:001PO_L2 1401UC
答案1
没有一个通用函数可以vlookup
像 Unix 中的通用函数一样执行 a 操作。相反,您提供的是“砖块”,您可以通过这些“砖块”以更加定制的方法构建问题的解决方案。这些“砖块”是诸如grep
、awk
、sed
等工具。
其中一种工具awk
可以使用如下:
vlookup.awk
FNR==NR{
a[$1]=$2
next
}
{ if ($1 in a) {print $1, a[$1]} else {print $1, "NA"} }
例子
$ awk -f vlookup.awk file2 file1
1GR_P1:001PI 1GR_P1:001PI
:040VG_L1 NA
:001PO_L3 NA
1JPI_P1:001PO_L1 1JPI_P1:001PO_L1
1JPI_P1:001PO_L2 1JPI_P1:001PO_L2
您可以使用以下column
命令来清理输出:
$ awk -f vlookup.awk file2 file1 | column -t
1GR_P1:001PI 1GR_P1:001PI
:040VG_L1 NA
:001PO_L3 NA
1JPI_P1:001PO_L1 1JPI_P1:001PO_L1
1JPI_P1:001PO_L2 1JPI_P1:001PO_L2
细节
上面的awk
脚本将 file2 的所有内容放入一个数组中,该数组使用值作为键进行索引。
a[$1]=$1
一旦file2
被读入 array a
,file1
然后一次浏览一行并做出决定。如果file1
数组中存在第一列的值a
,则第 2 列中的相应值file2
将与第 1 列一起打印。file1
如果不存在,则打印“NA”消息。
答案2
POSIXjoin(1)
命令执行的操作与 非常相似VLOOKUP()
,但需要注意的是输入文件必须已经在要连接的列上排序。
$ sort file1 > sfile1
$ sort file2 > sfile2
$ join -a1 sfile1 sfile2
1GR_P1:001PI 1402UC
1JPI_P1:001PO_L1 1401UC
1JPI_P1:001PO_L2 1401UC
:001PO_L3
:040VG_L1
不幸的是,您的示例并没有真正说明如何join
工作,因为file1
只包含一列。
为了准确获得您想要的输出,您可以使用关联数组编写一个简单的脚本,例如awk
,正如其他人所建议的那样。
答案3
对于您提供的具体数据示例,以下内容应该有效。它将字段 2 加载到File2
由字段 1 索引的数组中。File1
然后循环并数组匹配或NA
打印
awk 'NR == FNR{a[$1] = $2;next}; {print $1, $1 in a?a[$1]: "NA"}' File2 File1
答案4
尝试混合使用 awk 和 redis(一种非常快速的开源 NoSQL 键值存储。请参阅http://redis.io了解详情)。
使用 awk 解析 2 个文件以生成 redis 命令。
将 2 个 awk 脚本的结果通过管道传输到 bash 中来执行它们。就是这样 :-)
一步步:
通过解析“File2”来生成 redis“SET”语句,如下所示:
awk '{print "redis-cli SET KEY:" $1 " \"" $2"\""}' File2
redis-cli SET KEY:1JPI_P1:001PO_L1 "1401UC"
redis-cli SET KEY:1JPI_P1:001PO_L2 "1401UC"
redis-cli SET KEY:1HIK_P2:001ER "1402UC"
redis-cli SET KEY:1GR_P1:001PI "1402UC"
将生成的 redis“SET”语句通过管道传输到 bash 中以执行它们:
awk '{print "redis-cli SET KEY:" $1 " \"" $2"\""}' File2 |\
bash
OK
OK
OK
OK
通过解析“File1”生成 redis“GET”语句,如下所示:
awk '{print "printf \"" $1 " \" && redis-cli GET KEY:" $1}' File1
printf "1GR_P1:001PI " && redis-cli GET KEY:1GR_P1:001PI
printf ":040VG_L1 " && redis-cli GET KEY::040VG_L1
printf ":001PO_L3 " && redis-cli GET KEY::001PO_L3
printf "1JPI_P1:001PO_L1 " && redis-cli GET KEY:1JPI_P1:001PO_L1
printf "1JPI_P1:001PO_L2 " && redis-cli GET KEY:1JPI_P1:001PO_L2
现在通过将上面生成的 redis“GET”语句传输到 bash 来查询 redis:
awk '{print "printf \"" $1 " \" && redis-cli GET KEY:" $1}' File1 |\
bash
1GR_P1:001PI "1402UC"
:040VG_L1 (nil)
:001PO_L3 (nil)
1JPI_P1:001PO_L1 "1401UC"
1JPI_P1:001PO_L2 "1401UC"
请注意,您需要使用单反斜杠转义字符串中的双引号,以避免 redis 导入错误(请参阅 slm 的答案如何修改这个 Perl 解决方案,以便它将嵌入的双引号替换为单引号?)。如果您的值包含大量双引号,您还可以使用单引号封装您的值以导入到 Redis 中。
华泰
伯尼