假设我有一个巨大的文本文件,如下所示:
19990231
blabla
sssssssssssss
hhhhhhhhhhhhhh
ggggggggggggggg
20090812
blbclg
hhhhhhhhhhhhhh
ggggggggggggggg
hhhhhhhhhhhhhhh
20010221
fgghgg
sssssssssssss
hhhhhhhhhhhhhhh
ggggggggggggggg
<etc>
如何随机删除100个以数字字符开头并以空行结束的块?例如:
20090812
blbclg
hhhhhhhhhhhhhh
ggggggggggggggg
hhhhhhhhhhhhhhh
<blank line>
答案 0 :(得分:3)
这并不困难。诀窍是首先定义记录,这可以使用记录分隔符完成:
RS
:RS
字符串值的第一个字符应为输入记录分隔符;默认情况下为<newline>
。如果RS
包含多个字符,则结果未指定。 如果RS
为空,则记录由包含<newline>
加上一个或多个空行的序列分隔,前导或尾随空白行不应导致在开头或结尾处的空记录输入,<newline>
始终是字段分隔符,无论FS
的值是什么。
所以记录的数量由:
给出$ NR=$(awk 'BEGIN{RS=""}END{print NR}' <file>)
然后,您可以使用shuf
在1和NR
之间获得一百个随机数:
$ shuf -i 1-$NR -n 100
您可以在awk
中再次输入此命令以选择记录:
$ awk -v n=100 '(NR==n){RS="";ORS="\n\n"} # reset the RS for reading <file>
(NR==FNR){print $1; a[$1];next} # load 100 numbers in memory
!(FNR in a) { print } # print records
' <(shuf -i 1-$NR -n 100) <file>
我们也可以使用Knuth shuffle一次性执行此操作并执行文件的双重传递
awk -v n=100 '
# Create n random numbers between 1 and m
function shuffle(m,n, b, i, j, t) {
for (i = m; i > 0; i--) b[i] = i
for (i = m; i > 1; i--) {
# j = random integer from 1 to i
j = int(i * rand()) + 1
# swap b[i], b[j]
t = b[i]; b[i] = b[j]; b[j] = t
}
for (i = n; i > 0; i--) a[b[i]]
}
BEGIN{RS=""; srand()}
(NR==FNR) {next}
(FNR==1) {shuffle(NR-1,n) }
!(FNR in a) { print }' <file> <file>
答案 1 :(得分:2)
使用 <dependency>
<groupId>org.apache.flink</groupId>
<artifactId>flink-runtime-web_${scala.binary.version}</artifactId>
<version>${flink.version}</version>
</dependency>
和awk
删除6个块中的4个块,其中每个块长3行:
shuf
只需将$ cat tst.awk
BEGIN { RS=""; ORS="\n\n" }
NR==FNR { next }
FNR==1 {
cmd = sprintf("shuf -i 1-%d -n %d", NR-FNR, numToDel)
oRS=RS; RS="\n"
while ( (cmd | getline line) > 0 ) {
badNrs[line]
}
RS=oRS
close(cmd)
}
!(FNR in badNrs)
$ awk -v numToDel=4 -f tst.awk file file
1
2
3
10
11
12
更改为numToDel=4
即可获得实际输入。
上面用于测试的输入文件是由:
生成的numToDel=100
产生:
$ seq 18 | awk '1; !(NR%3){print ""}' > file
答案 2 :(得分:1)
这是一个没有随机播放的解决方案
$ awk -v RS= -v ORS='\n\n' -v n=100 '
BEGIN {srand()}
NR==FNR{next}
FNR==1 {r[0];
while(length(r)<=n) r[int(rand()*NR)]}
!(FNR in r)' file{,}
双遍算法,第一轮是计算记录数,创建索引号的随机列表,达到所需值,打印不在列表中的记录。请注意,如果删除的数字更接近记录数,则性能会降低(获得新数字的概率会很低)。对于你的情况,600中的100个不会是一个问题。在另一种情况下,选择要打印的记录而不是删除记录会更容易。
由于shuf
非常快,我认为这不会给你带来性能提升,但这种方式可能更简单。