Перетасовка частей файла между маркерами - PullRequest
0 голосов
/ 31 октября 2018

У меня есть файлы, которые выглядят так:

asdasadsdasdas
dasdasdasdasd
asdas
dasd
asdas
das
das
das
das
das
#SHUFFLE_MARK_START
das
d
das
das
dasd
asd
asdas
das
das
afs
sf
#SHUFFLE_MARK_END
fas
fas
fas
fas
fas
fas
fas
fas

Я хочу перетасовать только часть файла между двумя маркерами - #SHUFFLE_MARK_START и #SHUFFLE_MARK_END, маркерами случайного использования может быть любая строка, которую я хочу, они просто должны быть уникальными для каждого файла, любые идеи, как это сделать в bash, так что эффективный?

Я уже пытался сделать это, делая что-то вроде

cat file | grep -P '.+#SHUFFLE_MARK_START' > start
cat file | grep -P '#SHUFFLE_MARK_START.+#SHUFFLE_MARK_FINISH' | shuff | > middle
cat file | grep -P '#SHUFFLE_MARK_FINISH.+' > end
echo start middle end > shuffled

но для больших файлов это довольно медленно, приведенные выше команды могут быть немного неправильными, так как я набираю их из памяти, просто чтобы показать идею

Ответы [ 3 ]

0 голосов
/ 31 октября 2018

awk на помощь! предполагает уникальные маркеры

$ awk '/#SHUFFLE_MARK_END/   {c++} 
                             {print > (FILENAME "." c+0)} 
       /#SHUFFLE_MARK_START/ {c++}' file
$ cat file.0 <(shuf file.1) file.2 > file.shuffled

трудно увидеть в случайном файле, здесь также есть тестовый скрипт

$ seq 20 | sed 's/11/#SHUFFLE_MARK_START/;s/16/#SHUFFLE_MARK_END/' > file
$ awk ...
$ cat file.0 <(shuf file.1) file.2

1
2
3
4
5
6
7
8
9
10
#SHUFFLE_MARK_START
14
15
13
12
#SHUFFLE_MARK_END
17
18
19
20

UPDATE

это комбинированный скрипт awk, без промежуточных файлов

$ awk '/#SHUFFLE_MARK_END/   {c++; close("shuf")} 
                             {if(c%2) print | "shuf"; else print}
       /#SHUFFLE_MARK_START/ {c++}' file

, который будет обрабатывать несколько (не пересекающихся) секций

для этого тестового файла

$ seq 20 | sed -E 's/1?3/#SHUFFLE_MARK_START/;s/1?7/#SHUFFLE_MARK_END/' > file

$ awk ... file

1
2
#SHUFFLE_MARK_START
5
6
4
#SHUFFLE_MARK_END
8
9
10
11
12
#SHUFFLE_MARK_START
14
16
15
#SHUFFLE_MARK_END
18
19
20
0 голосов
/ 01 ноября 2018

С GNU awk для совместных процессов и командой UNIX "shuf":

$ cat tst.awk
BEGIN { shuf="shuf" }
/^#SHUFFLE_MARK_END/ {
    close(shuf, "to")
    while ( (shuf |& getline line) > 0 ) {
        print line
    }
    close(shuf)
    inShuf=0
}
inShuf  { print |& shuf }
!inShuf { print }
/^#SHUFFLE_MARK_START/ { inShuf=1 }

.

$ awk -f tst.awk file
asdasadsdasdas
dasdasdasdasd
asdas
dasd
asdas
das
das
das
das
das
#SHUFFLE_MARK_START
sf
das
asdas
dasd
das
d
das
das
afs
das
asd
#SHUFFLE_MARK_END
fas
fas
fas
fas
fas
fas
fas
fas
0 голосов
/ 31 октября 2018

Вот скрипт на Perl, который делает это:

#!/usr/bin/perl
# Usage: foo.pl input.txt > output.txt
# or
# foo.pl < input.txt > output.txt
use warnings;
use strict;
use List::Util qw/shuffle/;
my $in_block = 0;
my @lines;
while (<>) {
  if (/#SHUFFLE_MARK_START/) {
    print;
    $in_block = 1;
  } elsif (/#SHUFFLE_MARK_END/) {
    print shuffle(@lines);
    print;
    $in_block = 0;
    @lines = ();
  } elsif ($in_block == 0) {
    print;
  } else {
    push @lines, $_;
  }
}

(Если вы не хотите включать строки #SHUFFLE_MARK_START и т. Д., Удалите соответствующие строки print;)

...