Jak mogę losowo ustawić linie w pliku przy użyciu standardowych narzędzi w systemie Red Hat Linux?

102

Jak mogę losowo ustawić linie w pliku przy użyciu standardowych narzędzi w systemie Red Hat Linux?

Nie mam z shufpolecenia, więc szukam czegoś niczym perlani awkjednego-liner, który wykonuje to samo zadanie.

Stuart Woodward
źródło
1
Zadałem prawie to samo pytanie [ stackoverflow.com/questions/286640/…
Steve Schnepp
Uważam gcc za standardowe narzędzie w każdym Linuksie. ; D
msb

Odpowiedzi:

64

I jeden wiersz w Perlu, który otrzymujesz!

perl -MList::Util -e 'print List::Util::shuffle <>'

Używa modułu, ale moduł jest częścią dystrybucji kodu Perla. Jeśli to nie wystarczy, możesz rozważyć zrobienie własnego.

Próbowałem użyć tego z -iflagą („edycja w miejscu”), aby edytować plik. Dokumentacja sugeruje, że to powinno działać, ale tak nie jest. Nadal wyświetla przetasowany plik na standardowe wyjście, ale tym razem usuwa oryginał. Sugeruję, żebyś go nie używał.

Rozważmy skrypt powłoki:

#!/bin/sh

if [[ $# -eq 0 ]]
then
  echo "Usage: $0 [file ...]"
  exit 1
fi

for i in "$@"
do
  perl -MList::Util -e 'print List::Util::shuffle <>' $i > $i.new
  if [[ `wc -c $i` -eq `wc -c $i.new` ]]
  then
    mv $i.new $i
  else
    echo "Error for file $i!"
  fi
done

Niesprawdzone, ale mam nadzieję, że działa.

Chris Lutz
źródło
Aby wykonać kopię zapasową oryginalnego pliku, możesz dodać rozszerzenie do flagi -i [ perldoc.perl.org/perlrun.html]
Steve
Zwykle jestem fanem Perl, ale natknąłem się na ten przykład ruby który ma tę zaletę, że jest krótszy: ruby -e 'puts STDIN.readlines.shuffle'. Konieczne byłoby przetestowanie dużych danych wejściowych, aby sprawdzić, czy prędkość jest porównywalna. (działa również na OS X)
mivk
zgodnie z komentarzem poniżej, shufładuje wszystko do pamięci, więc nie działa z naprawdę dużym plikiem (mój to ~ 300GB tsv). Ten skrypt Perla również zawiódł na moim, ale bez błędu poza Killed. Masz jakiś pomysł, czy rozwiązanie Perla ładuje również wszystko do pamięci, czy jest jakiś inny problem, z którym się spotykam?
seth127
211

Nie zapominajmy

sort --random-sort
Jim T.
źródło
1
Cóż, używam gnu-coreutils 7.1 (standardowa instalacja gentoo), która ma sortowanie z tą opcją, nie jestem pewien, kiedy się pojawiła, lub czy jest w innych implementacjach.
Jim T
1
Funkcja została wprowadzona 10 grudnia 2005 r., A następnym wydaniem było 5.94, więc domyślam się, że była dostępna od tamtej wersji.
Jim T
41
W systemie OS X możesz zainstalować coreutils gnu za pomocą homebrew: brew install coreutilswszystkie narzędzia mają przedrostek ag so: gsort --random-sortlub gshufbędą działać zgodnie z oczekiwaniami
mike
3
+1 @mike. Używam Macports, a także miałem gsorti gshufzainstalowałem, kiedy to zrobiłemport install coreutils
Noah Sussman
10
To rozwiązanie jest dobre tylko wtedy, gdy twoje linie nie mają powtórzeń. Jeśli tak, wszystkie wystąpienia tej linii pojawią się obok siebie. Rozważ użycie shufzamiast tego (w systemie Linux).
Ali J
119

shuf to najlepszy sposób.

sort -Rjest boleśnie powolny. Właśnie próbowałem posortować plik 5 GB. Zrezygnowałem po 2,5 godziny. Następnie shufposortowałem to w minutę.

Michał Illich
źródło
To jest świetne. Wygląda na to, że znajduje się w coreutils GNU.
ariddell
4
Podejrzewam, że powód sort -Rjest powolny, ponieważ oblicza skrót dla każdego wiersza. Z dokumentacji: „ Sortuj, mieszając klucze wejściowe, a następnie sortuj wartości skrótu.
Joe Flynn
14
uważaj, shufładuje wszystko do pamięci.
jfs
1
@benroth: Z tego, co mogę powiedzieć, przy naprawdę dużych liczbach wejściowych zwiększenie pamięci może nieco pomóc , ale ogólnie nadal jest wolne. W moich testach sortowanie pliku wejściowego o długości 1 miliona linii utworzonego za pomocą seq -f 'line %.0f' 1000000tego samego, długiego czasu (dużo, dużo dłużej niż w przypadku shuf), bez względu na to, ile przydzieliłem pamięci.
mklement0
1
@ mklement0, masz rację! Po prostu wypróbowałem to z dużo większym plikiem niż ten, który miałem wcześniej i haszowanie wydaje się być rzeczywiście wąskim gardłem.
benroth
23
cat yourfile.txt | while IFS= read -r f; do printf "%05d %s\n" "$RANDOM" "$f"; done | sort -n | cut -c7-

Przeczytaj plik, uzupełnij każdą linię losową liczbą, posortuj plik według tych losowych prefiksów, a następnie wytnij przedrostki. Jednowarstwowy, który powinien pasować do każdego pół-nowoczesnego skorupy.

EDYCJA: włączone uwagi Richarda Hansena.

ChristopheD
źródło
1
To działa i jest kreatywnym rozwiązaniem, ale usunie wiodące spacje w wierszach.
Chris Lutz
@Chris zmieniając ostatnie cięcie na | sed 's / ^ [^ \ t] * \ t //' powinno to naprawić
bdonlan
Uznanie dla prostoty podejścia!
Shashikant Kore
3
+1 dla zgodności z POSIX (z wyjątkiem $RANDOM), ale -1 dla zniszczenia danych. Zastąpienie while read fprzez while IFS= read -r fzapobiegnie readusunięciu wiodących i końcowych białych znaków (zobacz tę odpowiedź ) i zapobiegnie przetwarzaniu odwrotnych ukośników. Użycie losowego ciągu o stałej długości zapobiegnie cutusunięciu wiodących białych znaków. Wynik: cat yourfile.txt | while IFS= read -r f; do printf "%05d %s\n" "$RANDOM" "$f"; done | sort -n | cut -c7-
Richard Hansen
3
@Richard Hansen: Dzięki, te sugerowane zmiany są oczywiście odpowiednie, zredagowałem swój post.
ChristopheD,
9

Jednowierszowy dla Pythona:

python -c "import random, sys; lines = open(sys.argv[1]).readlines(); random.shuffle(lines); print ''.join(lines)," myFile

A do wydrukowania tylko jednej losowej linii:

python -c "import random, sys; print random.choice(open(sys.argv[1]).readlines())," myFile

Ale zobacz ten post, aby poznać wady Pythona random.shuffle(). Nie będzie działać dobrze z wieloma (ponad 2080) elementami.

scai
źródło
5

Powiązane z odpowiedzią Jima:

Mój ~/.bashrczawiera następujące elementy:

unsort ()
{
    LC_ALL=C sort -R "$@"
}

Z sortowaniem GNU coreutils -R= --random-sort, które generuje losowy skrót z każdej linii i sortuje według niego. Losowy hash nie byłby faktycznie używany w niektórych lokalizacjach w niektórych starszych (błędnych) wersjach, powodując zwracanie normalnych posortowanych danych wyjściowych, dlatego ustawiłem LC_ALL=C.


Powiązane z odpowiedzią Chrisa:

perl -MList::Util=shuffle -e'print shuffle<>'

to nieco krótsza jednolinijka. ( -Mmodule=a,b,cjest skrótem od -e 'use module qw(a b c);'.)

Powodem, dla którego prostota jest prosta -i, nie działa w przypadku tasowania w miejscu, jest to, że Perl oczekuje, że printdzieje się to w tej samej pętli, w której plik jest odczytywany, i print shuffle <>nie jest wyprowadzany, dopóki wszystkie pliki wejściowe nie zostaną odczytane i zamknięte.

W ramach krótszego obejścia

perl -MList::Util=shuffle -i -ne'BEGIN{undef$/}print shuffle split/^/m'

będzie tasować pliki w miejscu. ( -noznacza „zawiń kod w while (<>) {...}pętlę; BEGIN{undef$/}powoduje , że Perl operuje na plikach w czasie zamiast na wierszach w czasie i split/^/mjest potrzebny, ponieważ $_=<>zostało niejawnie wykonane na całym pliku zamiast na wierszach).

ephemient
źródło
Powtarzając, że sort -R nie istnieje na OS X, ale +1 dla kilku świetnych odpowiedzi Perla i ogólnie świetnej odpowiedzi.
Chris Lutz
Możesz zainstalować GNU coreutils na OS X, ale (tak jak robiłem to w przeszłości) musisz uważać, aby nie złamać wbudowanych narzędzi ... To powiedziawszy, OP jest na Redhat Linux, który zdecydowanie ma GNU standard coreutils.
ephemient
3

Kiedy instaluję coreutils z homebrew

brew install coreutils

shufstaje się dostępny jako n.

John McDonnell
źródło
brew poprzedził wszystkie polecenia gtak shufstał się gshufdla mnie.
Jörn
^ Czy to dlatego, że nie są zgodne z POSIX, czy też jestem całkowicie wyłączony?
Dave Liu
1

Mac OS X z DarwinPorts:

sudo port install unsort
cat $file | unsort | ...
Coroos
źródło
1

FreeBSD ma własne losowe narzędzie:

cat $file | random | ...

Jest w / usr / games / random, więc jeśli nie masz zainstalowanych gier, nie masz szczęścia.

Możesz rozważyć zainstalowanie portów takich jak textproc / rand lub textproc / msort. Mogą być one dostępne w systemie Linux i / lub Mac OS X, jeśli problemem jest przenośność.

Coroos
źródło
-1

Na OSX pobieram najnowsze z http://ftp.gnu.org/gnu/coreutils/ i coś podobnego

./configure make sudo make install

... powinien dać ci / usr / local / bin / sort --random-sort

bez zepsucia / usr / bin / sort

Dan Brickley
źródło
to nie działało dla mnie na OSX (10.7). Otrzymałem komunikat „configure: błąd: kompilator C nie może tworzyć plików wykonywalnych”.
Dolan Antenucci
@dolan Sprawdź swoje uprawnienia?
Benubird
-1

Lub pobierz z MacPorts:

$ sudo port install coreutils

i / lub

$ /opt/local//libexec/gnubin/sort --random-sort
Chadwick Boggs
źródło