Это не так сложно.Хитрость заключается в том, чтобы сначала определить записи, и это можно сделать с помощью разделителя записей:
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>