Jaki jest łatwy sposób na odczytanie losowej linii z pliku w linii poleceń Uniksa?
linux
unix
random
command-line
codeforester
źródło
źródło
Odpowiedzi:
Możesz użyć
shuf
:Istnieje również narzędzie o nazwie
rl
. W Debianie jest wrandomize-lines
pakiecie, który robi dokładnie to, co chcesz, choć nie jest dostępny we wszystkich dystrybucjach. Na swojej stronie głównej zaleca używanieshuf
zamiast niej (jak sądzę, która nie istniała podczas jej tworzenia).shuf
jest częścią jądra GNU,rl
nie jest.źródło
shuf
wskazówkę, jest wbudowany w Fedorę.sort -R
pewnością sprawi, że będziesz musiał dużo czekać, jeśli poradzisz sobie z bardzo dużymi plikami - 80kk linii - podczas gdyshuf -n
działa dość natychmiastowo.coreutils
z Homebrew. Może być wywołanygshuf
zamiastshuf
.randomize-lines
w systemie OS X przezbrew install randomize-lines; rl -c 1 $FILE
shuf
jest częścią GNU Coreutils i dlatego niekoniecznie będzie dostępny (domyślnie) w systemach * BSD (lub Mac?). @ Perl one-liner poniżej programu Tracker1 jest bardziej przenośny (i według moich testów jest nieco szybszy).Inna alternatywa:
źródło
(${RANDOM} << 15) + ${RANDOM}
. To znacznie zmniejsza obciążenie i pozwala na pracę z plikami zawierającymi do 1 miliarda linii.+
i|
są takie same, ponieważ${RANDOM}
z definicji ma wartość 0..32767.(Jeszcze bardziej podoba mi się powyższe podejście shuf - nawet nie wiedziałem, że istnieje i nigdy nie znalazłbym tego narzędzia na własną rękę)
źródło
sort
, nie działał na żadnym z moich systemów (CentOS 5.5, Mac OS 10.7.2). Również bezużyteczne użycie kota można ograniczyć dosort --random-sort < $FILE | head -n 1
sort -R <<< $'1\n1\n2' | head -1
prawdopodobnie zwróci 1 i 2, ponieważsort -R
sortuje zduplikowane linie razem. To samo dotyczysort -Ru
, ponieważ usuwa duplikaty linii.sort
przed przesłaniem go do potokuhead
.shuf
zamiast tego wybiera losowe linie z pliku i jest dla mnie znacznie szybszy.sort --random-sort $FILE | head
byłoby najlepiej, ponieważ pozwala on na bezpośredni dostęp do pliku, prawdopodobnie umożliwiając wydajne sortowanie równoległe--random-sort
I-R
opcje są specyficzne dla GNU sort (więc nie będzie działać z BSD i Mac OSsort
). Sortowanie GNU nauczyło się tych flag w 2005 roku, więc potrzebujesz GNU coreutils 6.0 lub nowszego (np. CentOS 6).To jest proste.
To prawda, że jest to tylko odrobinę wolniej niż sam plik „shuf -n 1 file.txt”.
źródło
-n 1
określa 1 linię, i możesz zmienić ją na więcej niż 1.shuf
Można jej również użyć do innych rzeczy; Właśnie wykonałem potokps aux
igrep
za jego pomocą losowo zabiłem procesy częściowo pasujące do nazwy.perlfaq5: Jak wybrać losową linię z pliku? Oto algorytm próbkowania zbiornika z Księgi wielbłądów:
Ma to znaczną przewagę w przestrzeni kosmicznej nad wczytywaniem całego pliku. Dowód tej metody można znaleźć w The Art of Computer Programming, Tom 2, Rozdział 3.4.2, Donalda E. Knutha.
źródło
shuf
. Kod perlowy jest bardzo nieznacznie szybszy (8% szybszy w czasie użytkownika, 24% szybszy w czasie systemowym), choć anegdotycznie stwierdziłem, że kod perla „wydaje się” mniej przypadkowy (napisałem z niego szafę grającą).shuf
przechowuje cały plik wejściowy w pamięci , co jest okropnym pomysłem, podczas gdy ten kod przechowuje tylko jedną linię, więc limit tego kodu to liczba linii INT_MAX (2 ^ 31 lub 2 ^ 63 w zależności od twojego arch), zakładając, że dowolna z wybranych linii potencjalnych mieści się w pamięci.za pomocą skryptu bash:
źródło
Linia pojedynczego uderzenia:
Nieznaczny problem: zduplikowana nazwa pliku.
źródło
wc -l < test.txt
unika konieczności rurek docut
.Oto prosty skrypt w języku Python, który wykona zadanie:
Stosowanie:
źródło
import random, sys lines = open(sys.argv[1]).readlines()
dla i w zakresie (len (linie)): rand = random.randint (0, len (linie) -1) print lines.pop (rand),len(lines)
może prowadzić do IndexError. Możesz użyćprint(random.choice(list(open(sys.argv[1]))))
. Istnieje również efektywny pod względem pamięci algorytm próbkowania zbiornika .Innym sposobem jest użycie „ awk ”
źródło
$RANDOM
to bashism ). Oto czysta metoda awk (mawk) wykorzystująca tę samą logikę, co cytowany powyżej kod perlfaq5 @ Tracker1:awk 'rand() * NR < 1 { line = $0 } END { print line }' file.name
(wow, jest nawet krótszy niż kod perl!)wc
) w celu uzyskania liczby wierszy, a następnie musi ponownie odczytać (część) pliku (awk
), aby uzyskać zawartość podanego losowego numeru wiersza. We / wy będzie znacznie droższe niż uzyskanie liczby losowej. Mój kod czyta plik tylko raz. Problem z awkrand()
polega na tym, że uruchamia się on na podstawie sekund, więc otrzymasz duplikaty, jeśli uruchomisz go zbyt szybko.Rozwiązanie, które działa również w systemie MacOSX i powinno również działać w systemie Linux (?):
Gdzie:
N
to liczba losowych linii, którą chceszNR==FNR {lineN[$1]; next}(FNR in lineN) file1 file2
-> zapisz numery linii zapisane,file1
a następnie wydrukuj odpowiednią linięfile2
jot -r $N 1 $(wc -l < $file)
-> losujN
liczby losowo (-r
) w zakresie(1, number_of_line_in_file)
odjot
. Podstawienie procesu<()
sprawi, że będzie wyglądać jak plik dla interpretera, tak jakfile1
w poprzednim przykładzie.źródło
źródło
Oto, co odkrywam, ponieważ mój system Mac OS nie używa wszystkich łatwych odpowiedzi. Użyłem polecenia jot do wygenerowania liczby, ponieważ zmienne $ RANDOM nie wydają się być zbyt losowe w moim teście. Podczas testowania mojego rozwiązania miałem dużą różnorodność rozwiązań dostarczonych w danych wyjściowych.
Echo zmiennej ma na celu uzyskanie wizualnej wygenerowanej liczby losowej.
źródło
Używając tylko waniliowej sed i awk oraz bez użycia $ RANDOM, prosty, zajmujący mało miejsca i stosunkowo szybki „jeden wiersz” do wybierania pseudolosowego pojedynczego wiersza z pliku o nazwie FILENAME jest następujący:
(Działa to nawet wtedy, gdy FILENAME jest pusta, w którym to przypadku nie jest emitowany żaden wiersz).
Jedną z możliwych zalet tego podejścia jest to, że wywołuje on rand () tylko raz.
Jak wskazał @AdamKatz w komentarzach, inną możliwością byłoby wywołanie rand () dla każdej linii:
(Prosty dowód poprawności można podać na podstawie indukcji.)
Zastrzeżenie dotyczące
rand()
„W większości implementacji awk, w tym gawk, rand () zaczyna generować liczby z tego samego numeru początkowego lub początkowego za każdym razem, gdy uruchamiasz awk.”
- https://www.gnu.org/software/gawk/manual/html_node/Numeric-Functions.html
źródło