Объединение файлов построчно

Чтобы расширить ответ @RoVo, вы можете использовать цикл for для повторения всех ваших запросов:

for term in "kwd1" "kwd2" "kwd3" "kwd4" "kwd5"; do
    grep "$term" search_file.txt || echo "string"`
done
0
21.04.2021, 16:23
4 ответа

Вы можете использовать для этого paste, просто установите разделитель на новую строку:

$ paste -d'\n' file1 file2 file3
A 
E 
I 
B 
F
J
C 
G
K
D 
H
L
10
28.04.2021, 22:51
#!/usr/bin/perl

use strict;

# how many files to open? 10 in the question, 3 in examples.
my $numfh=3;

# a counter for the number of open file handles
my $openfh=$numfh;

# open an array of filehandles, one for each input file.
my @fh = ();
for my $i (1..$numfh) {
  open($fh[$i],"<","file$i.txt") || die "Couldn't open file$i.txt for read: $!";
};

# open the output file.
open (my $out,">","bigfile.txt") || die "Couldn't open bigfile.txt for write: $!";

# repeat until there are no more open file handles.
until ($openfh < 1) {
  for my $i (1..$numfh) {
    if (eof($fh[$i])) {
      # if an input file is eof, close it and decrement openfh counter.
      $openfh--;
      close($fh[$i]);
    } else {
      # print a line of input from the current input file to the output file.
      print $out scalar readline $fh[$i]
    };
  };
}

Сохраните это как, например, merge.plи сделайте его исполняемым с помощью chmod +x merge.pl. Затем запустите его вот так:

$./merge.pl

Выход:

$ cat bigfile.txt 
A
E
I
B
F
J
C
G
K
D
H
L

а вот версия с использованием @ARGV и выводом в STDOUT для @terdon:

#!/usr/bin/perl

use strict;

my @fh = ();
my $i=1;

for my $f (@ARGV) {
  open($fh[$i++], "<", $f) || die "Couldn't open $f for read: $!";
};

my $numfh=$#fh; my $openfh=$numfh;

until ($openfh < 1) {
  for my $i (1..$numfh) {
    if (eof($fh[$i])) {
      $openfh--;
      close($fh[$i]);
    } else {
      print scalar readline $fh[$i]
    };
  };
}

Или использовать хеш для хранения дескрипторов файлов вместо массива:

#!/usr/bin/perl

use strict;

my %fh = ();

for (@ARGV) {
  open($fh{$_}, "<", $_) || die "Couldn't open $_ for read: $!";
};

while (keys %fh) {
  for my $f (@ARGV) {
    next unless (defined($fh{$f}));
    if (eof($fh{$f})) {
      close($fh{$f});
      delete($fh{$f});
    } else {
      print scalar readline $fh{$f}
    };
  };
}

Запустите как:

$./merge.pl file[123].txt > bigfile.txt

Вывод идентичен жестко закодированной -версии.

1
28.04.2021, 22:51

Вот альтернатива paste(, протестированная с GNU prи оболочкой, поддерживающей ANSI -C, цитирующая)

pr -mts$'\n' <files>

Одним из преимуществ является то, что опция -sбудет работать и для многосимвольного разделителя.


Поскольку sedпомечен, вы можете использовать Rкоманду (, доступную на GNU sed, не уверен в других реализациях ).

sed -e 'R f2' -e 'R f3' f1
3
28.04.2021, 22:51

Используя GNU sed , мы можем использовать команду Rread для постепенного извлечения верхних строк из входных файлов для получения объединенного вывода.

sed -e "
  $(printf 'R%s\n' file{2..9}.txt file10.txt)
" file1.txt

perl -lne '
  push @{$A[@ARGV]}, $_}{
  for my $i (0..$#{$A[0]}){
    print for map { $A[$_][$i] } reverse 0..$#A
  }
' file{1..9}.txt file10.txt

Здесь мы храним файлы в AoA, также известном как двумерный массив @A. Первый индекс относится к позиции файла в списке позиционных аргументов, а второй индекс относится к данным этого конкретного файла. В конечном блоке }{мы сжимаем массив, выбирая один элемент из каждого массива.

1
28.04.2021, 22:51

Теги

Похожие вопросы