unix中的vlookup函数

unix中的vlookup函数

如何在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 操作。相反,您提供的是“砖块”,您可以通过这些“砖块”以更加定制的方法构建问题的解决方案。这些“砖块”是诸如grepawksed等工具。

其中一种工具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 afile1然后一次浏览一行并做出决定。如果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 中。

华泰

伯尼

相关内容