在标记之间洗牌文件的各个部分
Shuffling parts of a file between markers
我有这样的文件:
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
但是对于大文件来说速度很慢,上面的命令可能有点错误,因为我是凭记忆输入它们只是为了展示想法
这是执行此操作的 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;
行)
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
更新
这里是一个合并的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
使用用于协同进程的 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
我有这样的文件:
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
但是对于大文件来说速度很慢,上面的命令可能有点错误,因为我是凭记忆输入它们只是为了展示想法
这是执行此操作的 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;
行)
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
更新
这里是一个合并的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
使用用于协同进程的 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