Làm cách nào tôi có thể hợp nhất các tệp trên một dòng theo cơ sở?


22

tập tin mèo1

foo
ice
two

tập tin mèo2

bar
cream
hundred

Kết quả mong muốn:

foobar
icecream
twohundred

file1 và file2 sẽ luôn có cùng số lượng dòng trong kịch bản của tôi, trong trường hợp điều đó làm cho mọi thứ dễ dàng hơn.

Câu trả lời:


34

Công cụ phù hợp cho công việc này có lẽ là paste

paste -d '' file1 file2

Xem man pasteđể biết chi tiết.


Bạn cũng có thể sử dụng prlệnh:

pr -TmJS"" file1 file2

Ở đâu

  • -T tắt phân trang
  • -mJ m erge tập tin, J oining dòng đầy đủ
  • -S"" tách các cột bằng một chuỗi rỗng

Nếu bạn thực sự muốn làm điều đó bằng cách sử dụng shell bash thuần túy (không được khuyến nghị), thì đây là những gì tôi đề xuất:

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

(Chỉ bao gồm điều này bởi vì chủ đề đã đưa ra ý kiến ​​cho một giải pháp thuần túy được đề xuất khác.)


1
Tuyệt vời, cảm ơn bạn cho giải pháp rất đơn giản. Tôi có nên lo lắng về tính di động khi sử dụng dán không?
TuxForLife

1
@ user264974 dán trong GNU Coreutils nên có lẽ bạn khá an toàn.
nettux

8

Xuyên qua cách thức :

awk '{getline x<"file2"; print $0x}' file1
  • getline x<"file2" đọc toàn bộ dòng từ file2 và giữ thành biến x .
  • print $0xin toàn bộ dòng từ tệp1 bằng cách sử dụng $0sau xđó là dòng đã lưu của tệp2 .

Rất tốt để có một sự thay thế awk, tôi có thể sử dụng điều này thay thế!
TuxForLife

4

paste là con đường để đi . Nếu bạn muốn kiểm tra một số phương pháp khác, đây là một pythongiải pháp:

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

Nếu bạn có một vài dòng:

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

Lưu ý rằng đối với số dòng không bằng nhau, dòng này sẽ kết thúc ở dòng cuối cùng của tệp kết thúc trước.


3

Ngoài ra, với thuần túy bash(lưu ý rằng điều này sẽ hoàn toàn bỏ qua các dòng trống):

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

Đây chỉ là một lỗi bình thường. Nó hoàn toàn không hoạt động. Hoặc sử dụng mapfileđể đọc các tệp thành mảng hoặc sử dụng vòng lặp while với hai readlệnh, đọc từ mỗi fd của chúng.
geirha

@geirha Bạn nói đúng, tôi đã nhầm với cú pháp, giờ thì ổn rồi.
kos

không hẳn. Với mã được cập nhật, các dòng trống sẽ bị bỏ qua và nếu bất kỳ dòng nào chứa các ký tự toàn cục, dòng này có thể được thay thế bằng tên tệp phù hợp. Vì vậy, không bao giờ sử dụng array=( $(cmd) )hoặc array=( $var ). Sử dụng mapfilethay thế.
geirha

@geirha Tất nhiên là bạn đúng, tôi đã quan tâm đến các nhân vật toàn cầu nhưng tôi đã bỏ qua dòng mới, bởi vì để làm điều đó và để đưa ra một giải pháp hợp lý từ nó, nó cần phải được viết lại. Tôi đã chỉ định điều này và sẽ rời khỏi phiên bản này trong trường hợp nó sẽ hữu ích cho ai đó trong lúc này. Cảm ơn cho điểm của bạn cho đến nay.
kos

2

Cách perl, dễ hiểu:

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

Bắt đầu với:

./merge file1 file2

Đầu ra:

foobar
icecream
twohundred
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.