Jak mogę scalać pliki linia po linii?


22

plik kota 1

foo
ice
two

plik kota 2

bar
cream
hundred

Pożądane wyjście:

foobar
icecream
twohundred

plik1 i plik2 zawsze będą miały taką samą liczbę wierszy w moim scenariuszu, na wypadek, gdyby było to łatwiejsze.

Odpowiedzi:


34

Prawdopodobnie odpowiednie narzędzie do tego zadania paste

paste -d '' file1 file2

Zobacz man pasteszczegóły.


Możesz także użyć prpolecenia:

pr -TmJS"" file1 file2

gdzie

  • -T wyłącza paginację
  • -mJ m pliki Erge, J oining karta linii
  • -S"" rozdziel kolumny pustym ciągiem

Jeśli naprawdę chcesz to zrobić przy użyciu czystej powłoki bash (niezalecane), to właśnie sugeruję:

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

(Uwzględniając to tylko dlatego, że temat pojawił się w komentarzach do innego proponowanego rozwiązania czysto bash).


1
Wspaniale, dziękuję za bardzo proste rozwiązanie. Czy powinienem kiedykolwiek martwić się o przenośność, jeśli chodzi o używanie pasty?
TuxForLife

1
@ user264974 wklej jest w GNU Coreutils, więc prawdopodobnie jesteś dość bezpieczny.
nettux

8

Przez sposób:

awk '{getline x<"file2"; print $0x}' file1
  • getline x<"file2"wczytuje całą linię z pliku2 i przechowuje w zmiennej x .
  • print $0xwypisuje całą linię z pliku 1 , używając $0wtedy, xktóra jest zapisaną linią pliku 2 .

Bardzo dobrze, że mam alternatywę awk, mogę tego użyć!
TuxForLife,

4

pastejest droga . Jeśli chcesz sprawdzić inne metody, oto pythonrozwiązanie:

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

Jeśli masz kilka linii:

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

Zauważ, że w przypadku nierównej liczby wierszy ten kończy się na ostatnim wierszu pliku, który kończy się jako pierwszy.


3

Również z czystym bash(zauważ, że to całkowicie zignoruje puste linie):

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

To jest po prostu źle. To w ogóle nie działa. Albo użyj mapfiledo odczytu plików do tablic, albo użyj pętli while z dwoma readpoleceniami, odczytując z każdego ich fd.
geirha

@geirha Masz rację, pomyliłem się ze składnią, teraz jest w porządku.
Kos

nie do końca. W zaktualizowanym kodzie puste linie będą ignorowane, a jeśli jakikolwiek wiersz zawiera znaki globalne, wiersz może zostać zastąpiony pasującymi nazwami plików. Więc nigdy nie używaj array=( $(cmd) )lub array=( $var ). Użyj mapfilezamiast tego.
geirha

@geirha Masz oczywiście rację, zadbałem o globalne postacie, ale zostawiłem ignorowany nowy wiersz, ponieważ aby to zrobić i aby zrobić z niego przyzwoite rozwiązanie, trzeba go przepisać. Podałem to i zostawię tę wersję na wypadek, gdyby w międzyczasie przyda się komuś. Dzięki za dotychczasowe punkty.
Kos

2

Perlowy sposób, łatwy do zrozumienia:

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

Zacząć od:

./merge file1 file2

Wydajność:

foobar
icecream
twohundred
Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.