Как я могу объединять файлы построчно?

22

кошка file1

foo
ice
two

кошка file2

bar
cream
hundred

Желаемый вывод:

foobar
icecream
twohundred

file1 и file2 всегда будут иметь одинаковое количество строк в моем сценарии, на случай, если все будет проще.

TuxForLife
источник

Ответы:

34

Правильный инструмент для этой работы, вероятно, paste

paste -d '' file1 file2

Смотрите man pasteподробности.


Вы также можете использовать prкоманду:

pr -TmJS"" file1 file2

где

  • -T выключает нумерацию страниц
  • -mJ м Ерг файлы, J oining полных линии
  • -S"" разделить столбцы пустой строкой

Если вы действительно хотите сделать это с использованием чистой оболочки bash (не рекомендуется), то я бы предложил следующее:

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

(Только в том числе и потому, что тема появилась в комментариях к другому предложенному решению с чистым ударом.)

steeldriver
источник
1
Круто, спасибо за очень простое решение. Должен ли я когда-нибудь беспокоиться о переносимости, когда дело доходит до использования пасты?
TuxForLife
1
@ user264974 вставить в GNU Coreutils, так что вы, вероятно, в безопасности.
nettux
8

Через путь:

awk '{getline x<"file2"; print $0x}' file1
  • getline x<"file2"читает всю строку из file2 и удерживает переменную x
  • print $0xпечатает всю строку из файла file1 , используя $0затем, xкоторый является сохраненной строкой файла file2 .
αғsнιη
источник
Очень хорошо иметь альтернативу 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)))

Обратите внимание, что при неравном количестве строк эта заканчивается на последней строке файла, которая заканчивается первой.

heemayl
источник
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 с двумя readкомандами, считывая из каждого их fd.
Гейра
@geirha Вы правы, я перепутал синтаксис, теперь все нормально.
Кос
не совсем. При обновленном коде пустые строки будут игнорироваться, и, если какая-либо строка содержит символы глобуса, строка может быть заменена соответствующими именами файлов. Так что никогда не используйте array=( $(cmd) )или array=( $var ). Используйте mapfileвместо этого.
Гейра
@geirha Вы, конечно, правы, я позаботился о глобусных символах, но оставил символ новой строки игнорируемым, потому что для того, чтобы сделать это и найти достойное решение, его нужно переписать. Я указал это и оставлю эту версию на тот случай, если она кому-нибудь пригодится. Спасибо за ваши очки до сих пор.
Кос
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
AB
источник