Чтобы проверить, выполняется ли скрипт в интерактивной или -неинтерактивной оболочке, Я проверяю в своих скриптах наличие подсказки, хранящейся в переменной $PS1
:
if [ -z $PS1 ] # no prompt?
### if [ -v PS1 ] # On Bash 4.2+...
then
# non-interactive
...
else
# interactive
...
fi
Это я узнал здесь:https://www.tldp.org/LDP/abs/html/intandnonint.html
Это реализация решения в awk. Данные представляют собой 8 ГБ псевдо-случайных шестнадцатеричных цифр (, на самом деле шестнадцатеричное преобразование около 12 справочных страниц, продублированных 3300 раз ). Это около 11 миллионов строк, в среднем 725 байт на строку.
Это синхронизированное выполнение.
Paul--) ls -l tdHuge.txt
-rw-r--r-- 1 paul paul 8006529300 Dec 24 22:38 tdHuge.txt
Paul--)./rndSelect
inFile./tdHuge.txt; Size 8006529300; Count 10000; Lth 200; maxIter 50; Db 1;
Iteration 1 needs 10000
Iteration 2 needs 2712
Overlap 9561: 7663038508 to 7663038657
Iteration 3 needs 728
Iteration 4 needs 195
Iteration 5 needs 50
Iteration 6 needs 11
Iteration 7 needs 2
Required 7 iterations
Reporting 10000 samples
real 2m3.326s
user 0m3.496s
sys 0m10.340s
Paul--) wc Result.txt
20000 20000 2068894 Result.txt
Paul--) head -n 8 Result.txt | cut -c 1-40
>1
5706C69636174656420696E666F726D6174696F6
>2
20737472696E672028696E207768696368206361
>3
20646F6573206E6F742067657420612068617264
>4
647320616E642073746F7265732E204966207468
Paul--) tail -n 8 Result.txt | cut -c 1-40
>9997
6F7374207369676E69666963616E7420646F7562
>9998
7472696E676F702D73747261746567793D616C67
>9999
865726520736F6D652066696C6573206D7573742
>10000
5726E65642E205768656E20746865202D66206F7
Paul--)
Это требует итераций, потому что делает случайные проверки в файле. Если проба перекрывает соседнюю или новую строку, то она отбрасывается и создается меньшая партия новых проб. При средней длине строки 725 строк и требуемом количестве выборки 200 почти 30% зондов будут располагаться слишком близко к концу строки, чтобы их можно было принять. Мы не знаем среднюю длину строки реальных данных --, более длинные строки улучшат коэффициент успеха.
Мы также не знаем, присутствуют ли в файле строки заголовка (, как указано в предыдущем связанном вопросе от 04 -декабря -2020 ).Но при условии, что каждая строка заголовка меньше, чем длина выборки 200, строки заголовка будут отброшены (по счастливой случайности в лучшем случае ).
Код в основном представляет собой GNU/awk (минимальный bash )и содержит некоторые комментарии. Существует много остаточной отладки, которую можно скрыть, установив Db=0 в параметрах.
#! /bin/bash
#.. Select random non-overlapping character groups from a file.
export LC_ALL="C"
#.. These are the optional values that will need to be edited.
#.. Command options could be used to set these from scripts arguments.
inFile="./tdHuge.txt"
outFile="./Result.txt"
Count=10000 #.. Number of samples.
Lth=200 #.. Length of each sample.
maxIter=50 #.. Prevents excessive attempts.
Size="$( stat -c "%s" "${inFile}" )"
Seed="$( date '+%N' )"
Db=1
#.. Extracts random non-overlapping character groups from a file.
Selector () {
local Awk='
#.. Seed the random number generation, and show the args being used.
BEGIN {
NIL = ""; NL = "\n"; SQ = "\047";
srand (Seed % PROCINFO["pid"]);
if (Db) printf ("inFile %s; Size %d; Count %d; Lth %d; maxIter %s; Db %s;\n",
inFile, Size, Count, Lth, maxIter, Db);
fmtCmd = "dd bs=%d count=1 if=%s iflag=skip_bytes skip=%d status=none";
}
#.. Constructs an array of random file offsets, replacing overlaps.
#.. Existing offsets are indexed from 1 to Count, deleting overlaps.
#.. Additions are indexed from -1 down to -N to avoid clashes.
function Offsets (N, Local, Iter, nSeek, Seek, Text, j) {
while (N > 0 && Iter < maxIter) {
++Iter;
if (Db) printf ("Iteration %3d needs %6d\n", Iter, N);
for (j = 1; j <= N; ++j) {
Seek[-j] = int ((Size - Lth) * rand());
Text[Seek[-j]] = getSample( Seek[-j], Lth);
if (Db7) printf ("Added %10d: \n", Seek[-j], Text[Seek[-j]]);
}
#.. Reindex in numeric order for overlap checking.
nSeek = asort (Seek);
if (Db7) for (j in Seek) printf ("%6d: %10d\n", j, Seek[j]);
#.. Discard offsets that overlap the next selection.
N = 0; for (j = 1; j < nSeek; ++j) {
if (Seek[j] + Lth > Seek[j+1]) {
if (Db) printf ("Overlap %6d: %10d to %10d\n",
j, Seek[j], Seek[j+1]);
++N; delete Text[Seek[j]]; delete Seek[j];
} else if (length (Text[Seek[j]]) < Lth) {
if (Db7) printf ("Short %6d: %10d\n",
j, Seek[j]);
++N; delete Text[Seek[j]]; delete Seek[j];
}
}
}
if (Iter >= maxIter) {
printf ("Failed with overlaps after %d iterations\n", Iter);
} else {
printf ("Required %d iterations\n", Iter);
Samples( nSeek, Seek, Text);
}
}
#.. Returns n bytes from the input file from position p.
function getSample (p, n, Local, cmd, tx) {
cmd = sprintf (fmtCmd, n, SQ inFile SQ, p);
if (Db7) printf ("cmd :%s:\n", cmd);
cmd | getline tx; close (cmd);
return (tx);
}
#.. Send samples to the output file.
function Samples (nSeek, Seek, Text, Local, j) {
printf ("Reporting %d samples\n", nSeek);
for (j = 1; j <= nSeek; ++j) {
printf (">%d\n%s\n", j, Text[Seek[j]]) > outFile;
}
close (outFile);
}
END { Offsets( Count); }
'
echo | awk -v Size="${Size}" -v inFile="${inFile}" \
-v outFile="${outFile}" -v Count="${Count}" -v Lth="${Lth}" \
-v maxIter="${maxIter}" \
-v Db="${Db}" -v Seed="${Seed}" -f <( printf '%s' "${Awk}" )
}
#.. Test.
time Selector
РЕДАКТИРОВАТЬ :Я добавлю еще один ответ с реализацией (, которая может нуждаться в модификации ). Этот текущий ответ частично заменен, и я, вероятно, скоро захочу его удалить. Или, возможно, обновить его, как примечание к дизайну для фактической реализации.
Суть алгоритма. Он может не выдавать строго случайных результатов статистически, но, похоже, он удовлетворяет требованию. Вероятно, я бы прототипировал это в awk (, используя RNG Cliff, или, возможно, чтение из shuf ).
Установите N как количество смещений, которые будут добавлены к массиву X (, например. 10000 ).
Пока N > 0, итерации от 2a до 2d.
2а. Добавьте блок из N случайных смещений к X (, используя диапазон в вашем существующем скрипте ).
2б. Сортировка X по возрастанию.
2в. Перейдите X, сравнивая каждое смещение со следующим и помечая для удаления все, что ближе 200 символов от его преемника.
2д. Удалите отмеченные смещения и установите N равным количеству сделанных удалений.
На данный момент у нас есть 10000 случайных смещений (в порядке возрастания ), которые не перекрываются. (Нужна проверка того, что диапазон достаточно разрежен, чтобы этап 2 в конечном итоге вышел --, например, как минимум 3 *10000 *200 символов.)
3а. Выпустить серию 10000 хвост | команды головы (по одной на смещение ).
3б. Передайте эти команды через bash.
Сначала необходимо проверить, что диапазон достаточно разреженный, чтобы этап 2 в конечном итоге вышел из --, например, как минимум 3 *10000 *200 символов. Некоторые исследования по этому вопросу могут быть необходимы.
РЕДАКТИРОВАТЬ :Для проверки перекрытия между выборками требуются только смещения, а для проверки перекрытия с концом строки нужны данные. Итак, в (2a )прочитайте сам образец,и сохраните его в массиве, индексированном по смещению первого байта. Проверьте и удалите короткие сэмплы в (2c ).
Это делает весь (3 )избыточным, так как мы уже сохранили каждый допустимый образец в памяти (и у нас есть отсортированный список допустимых смещений для их индексации из ). Таким образом, мы можем просто перечислить все образцы в порядке смещения.