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.

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.)


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 .

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.


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

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
Dengan menggunakan situs kami, Anda mengakui telah membaca dan memahami Kebijakan Cookie dan Kebijakan Privasi kami.
Licensed under cc by-sa 3.0 with attribution required.