ฉันจะรวมไฟล์เป็นรายบรรทัดได้อย่างไร


22

cat file1

foo
ice
two

cat file2

bar
cream
hundred

ผลลัพธ์ที่ต้องการ:

foobar
icecream
twohundred

file1 และ file2 จะมีจำนวนบรรทัดเท่ากันเสมอในสถานการณ์ของฉันในกรณีที่ทำให้สิ่งต่าง ๆ ง่ายขึ้น

คำตอบ:


34

เครื่องมือที่เหมาะสมสำหรับงานนี้น่าจะเป็น paste

paste -d '' file1 file2

ดูman pasteรายละเอียดที่


คุณสามารถใช้prคำสั่ง:

pr -TmJS"" file1 file2

ที่ไหน

  • -T ปิดเลขหน้า
  • -mJ mลบไฟล์, J oining เต็มบรรทัด
  • -S"" แยกคอลัมน์ด้วยสตริงว่าง

หากคุณจริงๆอยากจะทำมันโดยใช้เปลือกทุบตีบริสุทธิ์ (ไม่แนะนำ) แล้วนี่คือสิ่งที่ผมขอแนะนำ:

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

(รวมถึงสิ่งนี้เท่านั้นเพราะหัวเรื่องแสดงความคิดเห็นต่อโซลูชัน pure-bash อื่นที่เสนอ)


1
เยี่ยมมากขอบคุณสำหรับวิธีแก้ปัญหาที่ง่ายมาก ฉันควรกังวลเกี่ยวกับการพกพาเมื่อใช้การวางหรือไม่
TuxForLife

1
@ user264974 paste อยู่ใน GNU Coreutils ดังนั้นคุณอาจค่อนข้างปลอดภัย
nettux

8

ผ่านทาง :

awk '{getline x<"file2"; print $0x}' file1
  • getline x<"file2"อ่านทั้งบรรทัดจากfile2และเก็บไว้ในตัวแปรx
  • print $0xพิมพ์สายทั้งจากfile1โดยใช้$0แล้วxซึ่งเป็นเส้นที่บันทึกไว้ของfile2

ดีมากที่มีทางเลือก awk ฉันอาจใช้สิ่งนี้แทน!
TuxForLife

4

pasteเป็นวิธีที่จะไป หากคุณต้องการตรวจสอบวิธีอื่น ๆ นี่คือpythonวิธีแก้ไข:

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

หากคุณมีจำนวนบรรทัดน้อย:

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

โปรดทราบว่าสำหรับจำนวนบรรทัดที่ไม่เท่ากันอันนี้จะสิ้นสุดที่บรรทัดสุดท้ายของไฟล์ที่ลงท้ายก่อน


3

นอกจากนี้ด้วยความบริสุทธิ์bash(โปรดสังเกตว่าสิ่งนี้จะละเว้นบรรทัดว่างเปล่าทั้งหมด)

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

นี่เป็นเพียงผิดธรรมดา มันไม่ทำงานเลย ใช้mapfileเพื่ออ่านไฟล์ในอาร์เรย์หรือใช้ while loop พร้อมreadคำสั่งสองคำสั่งอ่านแต่ละไฟล์ fd
geirha

@geirha คุณพูดถูกฉันยุ่งกับไวยากรณ์ตอนนี้ก็โอเค
kos

ไม่มาก ด้วยโค้ดที่อัปเดตบรรทัดว่างจะถูกละเว้นและหากบรรทัดใด ๆ มีอักขระ glob บรรทัดนั้นอาจถูกแทนที่ด้วยชื่อไฟล์ที่ตรงกัน ดังนั้นไม่เคยใช้หรือarray=( $(cmd) ) array=( $var )ใช้mapfileแทน
geirha

@geirha คุณถูกต้องแน่นอนฉันดูแลตัวละคร glob แต่ฉันออกจากบรรทัดใหม่ละเว้นเพราะเพื่อที่จะทำเช่นนั้นและเพื่อที่จะทำให้ทางออกที่ดีออกมาจากมันจะต้องมีการเขียนใหม่ ฉันระบุสิ่งนี้และจะปล่อยรุ่นนี้ในกรณีที่มีประโยชน์กับใครบางคนในระหว่างนี้ ขอบคุณสำหรับคะแนนของคุณ
kos

2

วิธี Perl ง่ายต่อการเข้าใจ:

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

เริ่มกับ:

./merge file1 file2

เอาท์พุท:

foobar
icecream
twohundred
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.