Compare strings em dois arquivos

0

Estou tentando obter o nome do usuário de um arquivo e seus detalhes correspondentes do meu outro arquivo. Eu uso o awk:

awk -F : '{ print $1 }' user-name

dá-me a lista de todos os usuários. Então, como posso combinar esses nomes com o outro arquivo e obter uma saída como:

user-name id contact-details

O formato dos dois arquivos é o seguinte:

1. nome do usuário

Tarun:143
Rahul:148
Neeraj:149

2. user-details

Tarun:[email protected]
Neeraj:[email protected]
Rahul:[email protected]

o que estou tentando conseguir é:

Neeraj:149:[email protected]
Rahul:148:[email protected]
Tarun:143:[email protected]
    
por Tarun 21.08.2014 / 07:55

5 respostas

4

Você pode usar o comando de junção

join -t ":" username contacts

o arquivo de nome de usuário tem o formato

user1:id1
user2:id2

os contatos têm o formato

user1:contact1
user2:contact2

Quando o arquivo não está classificado, você pode fazer o seguinte

sort -b username > username.sorted
sort -b contacts > contacts.sorted

e, em seguida, execute o comando de união em username.sorted e contacts.sorted

ou como outro post apontou que você pode fazer isso diretamente usando

join -t ":" <(sort -b username) <(sort -b contacts)
    
por Prathik Rajendran M 21.08.2014 / 09:02
4

Em um script python:

Uma solução pragmática

Caso seja um "trabalho único", específico para uma situação, os seguintes trabalhos:

#!/usr/bin/env python3

with open(file1) as names:
    names = sorted(names.readlines())
with open(file2) as data:
    data = data.readlines()
for i in names:
    item = i.replace("\n", "")+str([d[d.find(":"):].replace("\n", "") for d in data if d.startswith(i.split(":")[0])][0])
    print(item)

Saída:

Neeraj:149:[email protected]
Rahul:148:[email protected]
Tarun:143:[email protected]

Ou, se você quiser salvar a saída diretamente em um arquivo:

#!/usr/bin/env python3

with open(file1) as names:
    names = sorted(names.readlines())
with open(file2) as data:
    data = data.readlines()
with open(file3, "wt") as output:
    for i in names:
        output.write(i.replace("\n", "")+str([d[d.find(":"):].replace("\n", "") for d in data if d.startswith(i.split(":")[0])][0])+"\n")

Como você provavelmente sabe, copie o script em um arquivo vazio, defina o caminho para o arquivo 1-2 (3) (entre aspas), salve-o como combine.py , execute-o pelo comando:

python3 /path/to/combine.py

Uma solução mais digna de banco de dados

Olhando para os dois arquivos, estamos lidando com bancos de dados, com o primeiro campo como chave. O script a seguir é mais flexível e abrange uma maneira mais flexível de fazer relatórios dos dois arquivos, em situações (por exemplo) em que teríamos mais campos do que aqui é o caso.

Se adicionarmos um campo extra ("caracterizando") ao segundo arquivo:

Neeraj:[email protected]:Loves to Cook
Rahul:[email protected]:Collects empty bottles
Tarun:[email protected]:Weares his glasses upside down

Podemos querer adicionar a caracterização em vez do endereço de e-mail, ou ambos. Isso pediria um script como:

#!/usr/bin/env python3

db1 = "/path/to/file1"; db2 = "/path/to/file2"

with open(db1) as data1:
    rc = [l.replace("\n", "").split(":") for l in data1.readlines()]

with open(db2) as data2:
    records2 = [l.replace("\n", "").split(":") for l in data2.readlines()]

uniques = sorted(set(item[0] for item in rc)) # find keys
report = []

for i in uniques:
    database_1 = [r for r in rc if r[0] == i][0]
    database_2 = [r for r in records2 if r[0] == i][0]
    # -----------------------------------------------------------------------
    # set the required fields for report here:
    new_record = i, database_1[1], database_2[1]
    # -----------------------------------------------------------------------
    report.append((":").join(new_record))

for item in report:
    print(item)

Resultado

Se definirmos:

new_record = i, database_1[1], database_2[2]

O resultado é:

Neeraj:149:Loves to Cook
Rahul:148:Collects empty bottles
Tarun:143:Weares his glasses upside down

Mas se definirmos:

new_record = i, database_1[1], database_2[1]

O resultado é:

Neeraj:149:[email protected]
Rahul:148:[email protected]
Tarun:143:[email protected]

E se definirmos:

new_record = i, database_1[1], database_2[1], database_2[2]

O resultado é:

Neeraj:149:[email protected]:Loves to Cook
Rahul:148:[email protected]:Collects empty bottles
Tarun:143:[email protected]:Weares his glasses upside down
    
por Jacob Vlijm 21.08.2014 / 10:30
3

Com substituição de processos em bash , podemos fazer uma variante muito compacta da solução join mesmo para arquivos de entrada não classificados :

join -t: <(sort user-name) <(sort user-details)

A saída é como o exemplo de saída na pergunta:

Neeraj:149:[email protected]
Rahul:148:[email protected]
Tarun:143:[email protected]

Estamos usando o primeiro campo / coluna dos dois arquivos aqui. Para usar outras colunas, use as opções -1 e -2 (ou -j se for o mesmo campo). Para ser mais explícito, poderíamos usar join -t: -j 1 ... ou join -t: -1 1 -2 1 ... acima. (Veja também man join )

As partes do formulário <(command) são substituídas por um canal nomeado a partir do qual a saída do comando pode ser lida. Isso significa que, para o comando join , ele recebe dois arquivos com entradas classificadas como argumentos.

(Veja man bash | less '+/Process Substitution' )

    
por Volker Siegel 21.08.2014 / 12:07
2

Aqui está uma solução awk :

$ awk -F: -v OFS=: 'NR==FNR{a[$1]=$2; next}{print $1,a[$1],$2}' user-name user-details 
Tarun:143:[email protected]
Neeraj:149:[email protected]
Rahul:148:[email protected]

Explicação

  • -F: : define o separador de campo para : .
  • -v OFS=: : define o separador do campo de saída ( OFS ) como : para uma impressão bonita.
  • NR==FNR : NR é o número da linha atual e FNR é o número da linha do arquivo atual. Ao analisar mais de dois arquivos, NR será igual a FNR apenas para o primeiro arquivo. NR é incrementado para cada linha de entrada enquanto FNR é redefinido toda vez que um novo arquivo é lido.
  • {a[$1]=$2; next} : isso cria uma matriz associativa chamada a cuja chave é o primeiro campo e cujo valor é o segundo. Feito isso, passamos para a próxima linha com next .
  • {print $1,a[$1],$2} : imprima o primeiro campo dessa linha, o valor armazenado na matriz a desse campo e depois o segundo campo. Por causa do next explicado acima, isso só será executado quando NR não for igual a FNR . Em outras palavras, ele só será executado quando o segundo arquivo estiver sendo lido.
por terdon 21.08.2014 / 17:09
1

Experimente meu código:

Primeiro, classifique os dois user-name e contacts e escreva a saída em um arquivo chamado user-name_contacts com isso:

sort user-name contacts > user-name_contacts

Em seguida, execute este comando para unir dois arquivos:

sed -i '/$/N ; s/\n\(.*\):/:/' user-name_contacts


Saída:

 Neeraj:149:[email protected]
 Rahul:148:[email protected]
 Tarun:143:[email protected]
    
por sddgob 21.08.2014 / 09:58