Próbuję napisać skrypt powłoki. Chodzi o to, aby wybrać losowo pojedynczą linię z pliku tekstowego i wyświetlić ją jako powiadomienie na pulpicie Ubuntu.
Ale chcę, aby przy każdym uruchomieniu skryptu były wybierane różne wiersze. Czy jest na to jakieś rozwiązanie? Nie chcę całego skryptu. Tylko ta prosta rzecz.
scripts
text-processing
Anandu M Das
źródło
źródło
Odpowiedzi:
Możesz użyć
shuf
narzędzia do drukowania losowych linii z pliku-n
: liczba linii do wydrukowaniaPrzykłady:
źródło
n
liczby wierszy do wydrukowania. (tj. czy chcesz tylko jedną linię czy dwie linie). Nie numer wiersza (tj. Pierwszy wiersz, drugi wiersz).date +%S
) w zmiennej x, a następnie wybierz tę X linię za pomocą poleceńhead
itail
z pliku tekstowego. W każdym razie twoja metoda jest łatwiejsza. Dziękishuf
jest w coreutils, więc jest dostępny domyślnie. Uwaga: ładuje plik wejściowy do pamięci. Istnieje skuteczny algorytm, który go nie wymaga .Możesz także użyć
sort
polecenia, aby uzyskać losową linię z pliku.źródło
sort -R
daje inny wynik niżshuf -n1
lubselect-random
jeśli na wejściu znajdują się zduplikowane linie. Zobacz komentarz @ EliahKagan .Tak dla zabawy, tutaj jest czystą rozwiązanie bash , który nie korzysta
shuf
,sort
,wc
,sed
,head
,tail
lub jakiekolwiek inne narzędzia zewnętrzne.Jedyna przewaga nad
shuf
wariantem jest to, że jest nieco szybszy, ponieważ jest czystym uderzeniem. Na moim komputerze, dla pliku 1000 liniishuf
wariant zajmuje około 0,1 sekundy, podczas gdy poniższy skrypt zajmuje około 0,01 sekundy;) Tak więc, chociażshuf
jest to najłatwiejszy i najkrótszy wariant, jest on szybszy.Szczerze mówiąc nadal wybrałbym
shuf
rozwiązanie, chyba że wysoka wydajność jest ważnym problemem.źródło
shuf
jest znacznie lepsze. Myśląc o tym, nie wierzę, że czysty bash jest tak naprawdę bardziej wydajny niż używanieshuf
, jak wcześniej pisałem. Podczas uruchamiania zewnętrznego narzędzia może być najmniejszy (stały) narzut, ale wtedy będzie on działał mach szybciej niż interpretowane bash. Więc nashuf
pewno skaluje się lepiej. Powiedzmy, że skrypt służy celowi edukacyjnemu: Miło jest widzieć, że da się to zrobić;)shuf
specyficzny dla GNU Coreutils (np. Nie we FreeBSD 10.0).sort -R
jest przenośny, ale rozwiązuje inny (związany) problem: ciągi pojawiające się jako wiele linii mają prawdopodobieństwo równe tym, które pojawiają się tylko raz. (Oczywiście,wc
i inne narzędzia mogą być nadal używane.) Myślę, że głównym ograniczeniem tutaj jest to, że nigdy nie wybiera niczego po 32768 linii (i staje się mniej losowy nieco wcześniej).$((RANDOM<<15|RANDOM))
jest w zakresie 0..2 ^ 30-1. @JFSebastian Toshuf
nie jest taksort -R
, że skłania się ku częstszym wejściom. Umieścićshuf -n 1
w miejscusort -R | head -n1
i porównać. (Btw 10 ^ 3 iteracje są szybsze niż 10 ^ 6 i wciąż wystarczają, aby pokazać różnicę.) Zobacz także bardziej surowe, bardziej wizualne demo i ten odrobinę głupoty pokazujący, że działa na dużych wejściach, gdzie wszystkie struny mają wysoką częstotliwość .dieharder
wydają się składać się z samych zer. Zakładając, że nie jest to po prostu jakaś dziwna pomyłka z mojej strony, to z pewnością wyjaśnia, dlaczego nie jest przypadkowa! Czy otrzymujesz dobrze wyglądające dane, jeśli biegnieszwhile echo $(( RANDOM << 17 | RANDOM << 2 | RANDOM >> 13 )); do :; done | perl -ne 'print pack "I>"' > out
przez chwilę, a następnie sprawdzasz zawartośćout
edytora szesnastkowego? (Albo go zobaczyć jednak inny lubisz.) Pojawia się same zera, aRANDOM
nie jest winowajcą: mam same zera, gdy zastąpi$(( RANDOM << 17 | RANDOM << 2 | RANDOM >> 13 ))
się100
też.Powiedz, że masz plik
notifications.txt
. Musimy policzyć całkowitą liczbę linii, aby określić zakres generatora losowego:Napiszmy do zmiennej:
Teraz do wygenerowania liczby od
0
do$LINE
użyjemyRANDOM
zmiennej.Napiszmy do zmiennej:
Teraz musimy tylko wydrukować ten numer wiersza:
O firmie RANDOM:
Upewnij się, że plik ma mniej niż 32767 numerów linii. Zobacz to, jeśli potrzebujesz większego generatora losowego, który działa od razu po wyjęciu z pudełka.
Przykład:
źródło
LINES=$(wc -l < file.txt); R_LINE=$((RANDOM % LINES)); sed -n "${R_LINE}p" file.txt
$RANDOM % n
może wypaczyć losową dystrybucję, nawet jeśli$RANDOM
sama jest w porządku% n
do liczby losowej.Oto skrypt w języku Python, który wybiera losową linię z plików wejściowych lub standardowego wejścia:
Algorytm to czas O (n), przestrzeń O (1). Działa dla plików większych niż 32767 linii. Nie ładuje plików wejściowych do pamięci. Czyta każdą linię wejściową dokładnie raz, tzn. Można do niej wstawić dowolną dużą (ale skończoną) treść. Oto wyjaśnienie algorytmu .
źródło
Jestem pod wrażeniem pracy, którą wykonała Malte Skoruppa i inni, ale tutaj jest o wiele prostszy sposób „czystej bash”:
Jak niektórzy zauważyli, $ RANDOM nie jest przypadkowy. Jednak limit rozmiaru pliku wynoszący 32767 wierszy zostaje pokonany przez połączenie łańcuchów $ RANDOM w razie potrzeby.
źródło