Bagaimana saya bisa menggabungkan file pada basis per baris?

22

file cat1

foo
ice
two

file cat2

bar
cream
hundred

Output yang diinginkan:

foobar
icecream
twohundred

file1 dan file2 akan selalu memiliki jumlah baris yang sama dalam skenario saya, jika hal itu membuat segalanya lebih mudah.

TuxForLife
sumber

Jawaban:

34

Alat yang tepat untuk pekerjaan ini mungkin paste

paste -d '' file1 file2

Lihat man pastedetailnya.


Anda juga bisa menggunakan prperintah:

pr -TmJS"" file1 file2

dimana

  • -T mematikan pagination
  • -mJ m file erge, J garis penuh oining
  • -S"" pisahkan kolom dengan string kosong

Jika Anda benar - benar ingin melakukannya menggunakan shell bash murni (tidak disarankan), maka inilah yang saya sarankan:

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

(Hanya termasuk ini karena subjek muncul dalam komentar untuk solusi murni-bash yang diusulkan.)

Steeldriver
sumber
1
Luar biasa, terima kasih atas solusi yang sangat sederhana. Haruskah saya khawatir tentang portabilitas saat menggunakan pasta?
TuxForLife
1
@ user264974 tempel ada di GNU Coreutils sehingga Anda mungkin cukup aman.
nettux
8

Melalui cara :

awk '{getline x<"file2"; print $0x}' file1
  • getline x<"file2"membaca seluruh baris dari file2 dan menampung variabel x .
  • print $0xmencetak seluruh baris dari file1 dengan menggunakan $0maka xyang merupakan garis tersimpan file2 .
αғsнιη
sumber
Sangat bagus untuk memiliki alternatif awk, saya dapat menggunakan ini sebagai gantinya!
TuxForLife
4

pasteadalah cara untuk pergi . Jika Anda ingin memeriksa beberapa metode lain, berikut ini pythonsolusinya:

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

Jika Anda memiliki beberapa baris:

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

Perhatikan bahwa untuk jumlah baris yang tidak sama, baris ini akan berakhir di baris terakhir file yang berakhir lebih dulu.

heemayl
sumber
3

Juga, dengan pure bash(perhatikan bahwa ini benar-benar akan mengabaikan baris kosong):

#!/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
kos
sumber
Ini benar-benar salah. Itu tidak bekerja sama sekali. Baik digunakan mapfileuntuk membaca file ke dalam array, atau menggunakan loop sementara dengan dua readperintah, membaca dari masing-masing fd mereka.
geirha
@geirha Anda benar, saya mengacaukan sintaks, tidak apa-apa sekarang.
kos
tidak terlalu. Dengan kode yang diperbarui, baris kosong akan diabaikan, dan jika ada baris yang mengandung karakter glob, baris tersebut mungkin diganti dengan nama file yang cocok. Jadi jangan pernah gunakan array=( $(cmd) )atau array=( $var ). Gunakan mapfilesebagai gantinya.
geirha
@geirha Anda benar tentu saja, saya merawat karakter glob tetapi saya meninggalkan baris baru diabaikan, karena untuk melakukan itu dan untuk membuat solusi yang layak dari itu perlu ditulis ulang. Saya tentukan ini dan akan meninggalkan versi ini kalau-kalau itu akan berguna bagi seseorang sementara itu. Terima kasih atas poin Anda sejauh ini.
kos
2

Cara perl, mudah dimengerti:

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

Dimulai dari:

./merge file1 file2

Keluaran:

foobar
icecream
twohundred
AB
sumber