Como posso mesclar arquivos linha por linha?


22

file1 gato

foo
ice
two

file2 gato

bar
cream
hundred

Saída desejada:

foobar
icecream
twohundred

arquivo1 e arquivo2 sempre terão a mesma quantidade de linhas no meu cenário, caso isso facilite as coisas.

Respostas:


34

A ferramenta certa para este trabalho é provavelmente paste

paste -d '' file1 file2

Veja man pastepara detalhes.


Você também pode usar o prcomando:

pr -TmJS"" file1 file2

Onde

  • -T desativa a paginação
  • -mJ m ficheiros Erge, J linhas cheias oining
  • -S"" separar as colunas com uma sequência vazia

Se você realmente queria fazer isso usando o shell bash puro (não recomendado), é o que eu sugeriria:

while IFS= read -u3 -r a && IFS= read -u4 -r b; do 
  printf '%s%s\n' "$a" "$b"
done 3<file1 4<file2

(Somente incluindo isso porque o assunto surgiu nos comentários de outra solução de purificação de massa proposta).


1
Incrível, obrigado pela solução muito simples. Eu deveria me preocupar com a portabilidade quando se trata de usar colar?
TuxForLife

1
A pasta @ user264974 está no GNU Coreutils, então você provavelmente está bastante seguro.
Nettux 30/04/2015

8

Através da maneira :

awk '{getline x<"file2"; print $0x}' file1
  • getline x<"file2"lê a linha inteira do arquivo2 e mantém a variável x .
  • print $0ximprime a linha inteira do arquivo1 usando $0então xqual é a linha salva do arquivo2 .

Muito bom ter uma alternativa inábil, posso usar isso em seu lugar!
TuxForLife

4

pasteé o caminho a percorrer . Se você quiser verificar alguns outros métodos, aqui está uma pythonsolução:

#!/usr/bin/env python2
import itertools
with open('/path/to/file1') as f1, open('/path/to/file2') as f2:
    lines = itertools.izip_longest(f1, f2)
    for a, b in lines:
        if a and b:
            print a.rstrip() + b.rstrip()
        else:
            if a:
                print a.rstrip()
            else:
                print b.rstrip()

Se você tiver pouco número de linhas:

#!/usr/bin/env python2
with open('/path/to/file1') as f1, open('/path/to/file2') as f2:
    print '\n'.join((a.rstrip() + b.rstrip() for a, b in zip(f1, f2)))

Observe que, para um número desigual de linhas, este terminará na última linha do arquivo que termina primeiro.


3

Além disso, com pure bash(observe que isso ignorará totalmente as linhas vazias):

#!/bin/bash

IFS=$'\n' GLOBIGNORE='*'
f1=($(< file1))
f2=($(< file2))
i=0
while [ "${f1[${i}]}" ] && [ "${f2[${i}]}" ]
do
    echo "${f1[${i}]}${f2[${i}]}" >> out
    ((i++))
done
while [ "${f1[${i}]}" ]
do
    echo "${f1[${i}]}" >> out
    ((i++))
done
while [ "${f2[${i}]}" ]
do
    echo "${f2[${i}]}" >> out
    ((i++))
done

Isto é simplesmente errado. Não funciona de todo. Use mapfilepara ler os arquivos em matrizes ou use um loop while com dois readcomandos, lendo cada um deles.
Geirha 30/04

@geirha Você está certo, eu errei com a sintaxe, está tudo bem agora.
kos

não exatamente. Com o código atualizado, as linhas vazias serão ignoradas e, se alguma linha contiver caracteres glob, a linha poderá ser substituída por nomes de arquivos correspondentes. Portanto, nunca use array=( $(cmd) )ou array=( $var ). Use em mapfilevez disso.
Geirha 30/04

@geirha Você está certo, é claro, eu cuidei dos personagens globais, mas deixei a nova linha ignorada, porque para fazer isso e para criar uma solução decente, ela precisa ser reescrita. Especifiquei isso e deixarei esta versão, caso seja útil para alguém nesse meio tempo. Obrigado por seus pontos até agora.
kos

2

O jeito perl, fácil de entender:

#!/usr/bin/perl
$filename1=$ARGV[0];
$filename2=$ARGV[1];

open(my $fh1, "<", $filename1) or die "cannot open < $filename1: $!";
open(my $fh2, "<", $filename2) or die "cannot open < $filename2: $!";

my @array1;
my @array2;

while (my $line = <$fh1>) {
  chomp $line;
  push @array1, $line;
}
while (my $line = <$fh2>) {
  chomp $line;
  push @array2, $line;
}

for my $i (0 .. $#array1) {
  print @array1[$i].@array2[$i]."\n";
}

Começar com:

./merge file1 file2

Saída:

foobar
icecream
twohundred
Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.