Come posso unire i file riga per riga?


22

file cat1

foo
ice
two

cat file2

bar
cream
hundred

Uscita desiderata:

foobar
icecream
twohundred

file1 e file2 avranno sempre la stessa quantità di righe nel mio scenario, nel caso ciò semplifichi le cose.

Risposte:


34

Lo strumento giusto per questo lavoro è probabilmente paste

paste -d '' file1 file2

Vedi man pasteper i dettagli.


Puoi anche usare il prcomando:

pr -TmJS"" file1 file2

dove

  • -T disattiva l'impaginazione
  • -mJ m file si erge, J oining linee complete
  • -S"" separare le colonne con una stringa vuota

Se davvero volessi farlo usando pure bash shell (non raccomandato), allora questo è ciò che suggerirei:

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

(Includendo questo perché l'argomento è emerso nei commenti a un'altra proposta di soluzione pure-bash.)


1
Fantastico, grazie per la soluzione molto semplice. Dovrei mai preoccuparmi della portabilità quando si tratta di usare paste?
TuxForLife,

1
@ user264974 paste è in GNU Coreutils, quindi probabilmente sei abbastanza sicuro.
nettux,

8

Attraverso way:

awk '{getline x<"file2"; print $0x}' file1
  • getline x<"file2"legge l'intera riga da file2 e contiene la variabile x .
  • print $0xstampa l'intera riga da file1 utilizzando $0quindi xquale è la riga salvata di file2 .

Molto bello avere un'alternativa stravagante, potrei usare questo invece!
TuxForLife,

4

pasteè la strada da percorrere . Se vuoi controllare alcuni altri metodi, ecco una pythonsoluzione:

#!/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 hai un numero limitato di righe:

#!/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)))

Si noti che per un numero di righe diverso, questo termina all'ultima riga del file che termina per primo.


3

Inoltre, con pure bash(notare che questo ignorerà totalmente le righe vuote):

#!/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

Questo è semplicemente sbagliato. Non funziona affatto. Utilizzare mapfileper leggere i file in array o utilizzare un ciclo while con due readcomandi, leggendo da ciascuno il loro fd.
geirha,

@geirha Hai ragione, ho incasinato la sintassi, ora va bene.
kos

non proprio. Con il codice aggiornato, le righe vuote verranno ignorate e se una riga contiene caratteri glob, la riga potrebbe essere sostituita con nomi di file corrispondenti. Quindi non usare mai array=( $(cmd) )o array=( $var ). Usa mapfileinvece.
geirha,

@geirha Hai ragione, ovviamente, mi sono preso cura dei personaggi glob, ma ho lasciato il newline ignorato, perché per farlo e per farne una soluzione decente bisogna riscriverlo. Ho specificato questo e lascerò questa versione nel caso in cui sarà utile a qualcuno nel frattempo. Grazie per i tuoi punti finora.
kos

2

Il modo perl, facile da capire:

#!/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";
}

Iniziare con:

./merge file1 file2

Produzione:

foobar
icecream
twohundred
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.