função vlookup no unix

3

Como fazer algo semelhante à função vlookup do Excel no Unix?

trecho do site do escritório, VLOOKUP

The V in VLOOKUP stands for vertical. Use VLOOKUP instead of HLOOKUP when your comparison values are located in a column to the left of the data that you want to find.

Syntax VLOOKUP(lookup_value,table_array,col_index_num,range_lookup)

Lookup_value The value to search in the first column of the table array. Lookup_value can be a value or a reference. If lookup_value is smaller than the smallest value in the first column of table_array, VLOOKUP returns the #N/A error value.

Table_array Two or more columns of data. Use a reference to a range or a range name. The values in the first column of table_array are the values searched by lookup_value. These values can be text, numbers, or logical values. Uppercase and lowercase text are equivalent.

Col_index_num The column number in table_array from which the matching value must be returned. A col_index_num of 1 returns the value in the first column in table_array; a col_index_num of 2 returns the value in the second column in table_array, and so on. If col_index_num is:

Less than 1, VLOOKUP returns the #VALUE! error value. Greater than the number of columns in table_array, VLOOKUP returns the #REF! error value.

Range_lookup A logical value that specifies whether you want VLOOKUP to find an exact match or an approximate match:

Arquivo1:

1GR_P1:001PI
:040VG_L1
:001PO_L3
1JPI_P1:001PO_L1
1JPI_P1:001PO_L2

Arquivo2:

1JPI_P1:001PO_L1    1401UC
1JPI_P1:001PO_L2    1401UC
1HIK_P2:001ER       1402UC
1GR_P1:001PI        1402UC

Arquivo de saída3:

1GR_P1:001PI        1402UC
:040VG_L1       NA
:001PO_L3       NA
1JPI_P1:001PO_L1    1401UC
1JPI_P1:001PO_L2    1401UC
    
por ahmed 28.08.2013 / 16:10

5 respostas

6

Não existe uma função geral que faça um vlookup como uma função geral no Unix. Em vez disso, você está dando "tijolos", a partir dos quais você pode criar soluções para problemas em uma abordagem mais personalizada. Esses "tijolos" são ferramentas como grep , awk e sed entre outras.

Uma das ferramentas, awk , pode ser usada da seguinte forma:

vlookup.awk

FNR==NR{
  a[$1]=$2
  next
}
{ if ($1 in a) {print $1, a[$1]} else {print $1, "NA"}  }

Exemplo

$ 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

Você pode usar o comando column para limpar a saída:

$ 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

Detalhes

O script awk acima leva todo o conteúdo do arquivo2 para uma matriz que é indexada usando o valor como uma chave.

a[$1]=$1

Uma vez que file2 foi lido no array a , file1 é então passado por uma linha de cada vez e uma decisão é tomada. Se o valor da primeira coluna de file1 estiver presente na matriz a , o valor correspondente na coluna 2 de file2 será impresso junto com a coluna 1 de file1 . Se não estiver presente então a mensagem "NA" é impressa.

    
por 28.08.2013 / 17:02
1

Para os exemplos de dados específicos que você forneceu, o seguinte deve funcionar. Ele carrega o campo 2 de File2 em uma matriz indexada pelo campo 1. File1 é então passado em loop e correspondências de array ou NA são impressas

awk 'NR == FNR{a[$1] = $2;next}; {print $1, $1 in a?a[$1]: "NA"}' File2 File1
    
por 28.08.2013 / 16:42
1

O comando POSIX join(1) faz algo muito semelhante a VLOOKUP() , com a ressalva de que os arquivos de entrada já devem estar classificados nas colunas a serem unidas .

$ 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

Infelizmente, o seu exemplo não ilustra realmente como o join funciona, pois file1 contém apenas uma coluna.

Para obter exatamente a saída desejada, você pode escrever um script simples usando matrizes associativas, usando awk , por exemplo, como outras pessoas sugeriram.

    
por 28.08.2013 / 21:15
0

Se você estiver procurando por algo que funcione na linha de comando, consulte awk . Este é um programa muito popular usado para todos os tipos de operações de análise. link

Além disso, é difícil mencionar a análise de texto no UNIX sem mencionar grep . grep é usado para o texto correspondente à expressão regular. Embora não seja necessário para este aplicativo em particular, ele será útil se você estiver fazendo muita análise de texto. link

O uso de colunas de texto colrm pode ser cortado de um fluxo. Isso pode ser útil quando você está tendo problemas para isolar o texto com awk .

sed é o que você deseja usar se o texto a ser analisado for muito longo ou se o awk não conseguir realizar facilmente o que você deseja. Sed na Wikipédia

Tenho certeza de que estou perdendo dezenas, mas tudo que você precisa para este exemplo é awk , então está definido.

    
por 28.08.2013 / 16:40
0

Experimente uma mistura de awk e redis (um armazenamento de valor-chave NoSQL extremamente rápido e de código aberto. Veja link para detalhes).

Use o awk para analisar seus 2 arquivos para gerar seus comandos redis.

Pipe o resultado dos 2 scripts awk no bash para executá-los. É isso: -)

Passo a passo:

Gere suas instruções "SET" de redis analisando "File2" assim:

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"

Enfileire seus relatórios gerados "SET" para o bash para executá-los:

awk '{print "redis-cli SET KEY:" $1 " \"" $2"\""}' File2 |\
 bash
OK
OK
OK
OK

Gere suas declarações "GET" de redis analisando "File1" assim:

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

Agora consulta redis piping seus redis "GET" declarações geradas acima em bash:

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"

Tenha em atenção que precisa de aspas duplas nas suas cadeias com barras invertidas simples para evitar erros de importação de redis (consulte a resposta de slm em Como faço para modificar esta solução Perl para que ele irá substituir aspas duplas incorporadas com aspas simples? ). Você também pode usar aspas simples para encapsular seus valores para importação em redis, se seus valores estiverem contendo muitas aspas duplas.

HTH

bernie

    
por 29.08.2013 / 22:03