Fajnie, nie wiedziałem sort -R; Używałem Bogosort wcześniej :-p
alex
5
sort: nieprawidłowa opcja - R Spróbuj użyć `sort --help ', aby uzyskać więcej informacji.
2
Wydaje się, że nie działa w przypadku plików zawierających spacje.
Houshalter
Powinno to działać w przypadku plików ze spacjami (potok przetwarza linie). Nie działa w przypadku nazw zawierających znak nowej linii. Tylko użycie "$file", nie pokazane, byłoby wrażliwe na spacje.
OP chciał wybierać Nlosowe pliki, więc użycie 1jest nieco mylące.
aioobe
4
Jeśli masz nazwy plików z nowymi wierszami:find dirname -type f -print0 | shuf -zn1
Hitechcomputergeek
5
co się stanie, jeśli będę musiał skopiować te losowo wybrane pliki do innego folderu? jak wykonać operacje na tych losowo wybranych plikach?
Rishabh Agrahari
18
Oto kilka możliwości, które nie analizują wyniku programu lsi są w 100% bezpieczne w przypadku plików ze spacjami i zabawnymi symbolami w nazwie. Wszystkie z nich wypełnią tablicę randflistą losowych plików. W printf '%s\n' "${randf[@]}"razie potrzeby tablicę tę można łatwo wydrukować .
Ten prawdopodobnie wyprowadzi ten sam plik kilka razy i Nmusi być znany z wyprzedzeniem. Tutaj wybrałem N = 42.
a=(*)
randf=("${a[RANDOM%${#a[@]}]"{1..42}"}")
Ta funkcja nie jest dobrze udokumentowana.
Jeśli N nie jest znane z góry, ale bardzo podobała Ci się poprzednia możliwość, możesz użyć eval. Ale to jest złe i naprawdę musisz się upewnić, że Nnie pochodzi bezpośrednio z danych wejściowych użytkownika bez dokładnego sprawdzenia!
Uwaga . To jest późna odpowiedź na stary post, ale zaakceptowana odpowiedź prowadzi do zewnętrznej strony, która pokazuje okropnegrzmotnąćpraktyki, a druga odpowiedź nie jest dużo lepsza, ponieważ analizuje również wynik ls. Komentarz do zaakceptowanej odpowiedzi wskazuje na doskonałą odpowiedź Lhunatha, która oczywiście pokazuje dobrą praktykę, ale nie odpowiada dokładnie PO.
Pierwsza i druga spowodowały „złe zastąpienie”; nie podobało mu się, że "{1..42}"część pozostawia ślad "1". Ponadto $RANDOMjest tylko 15-bitowy, a metoda nie będzie działać z ponad 32767 plikami do wyboru.
Nie powinieneś polegać na wynikach ls. To nie zadziała, jeśli np. Nazwa pliku zawiera znaki nowej linii.
bfontaine,
3
@bfontaine wydajesz się nawiedzać przez znaki nowej linii w nazwach plików :). Czy naprawdę są tak powszechne? Innymi słowy, czy jest jakieś narzędzie, które tworzy pliki ze znakami nowej linii w nazwie? Ponieważ jako użytkownik bardzo trudno jest utworzyć taką nazwę pliku. To samo dotyczy plików pochodzących z internetu
Ciprian Tomoiagă
3
@CiprianTomoiaga To przykład problemów, które możesz napotkać. lsnie gwarantuje, że podasz "czyste" nazwy plików, więc nie powinieneś na tym polegać. Fakt, że te problemy są rzadkie lub niezwykłe, nie zmienia problemu; zwłaszcza biorąc pod uwagę, że istnieją lepsze rozwiązania tego problemu.
bfontaine
lsmoże zawierać katalogi i puste wiersze. find . -type f | shuf -n10Zamiast tego sugerowałbym coś takiego .
cherdt
9
Proste rozwiązanie do wybierania 5losowych plików bez analizowania ls . Działa również z plikami zawierającymi spacje, znaki nowej linii i inne znaki specjalne:
shuf -ezn 5*| xargs -0-n1 echo
Zastąp echopolecenie, które chcesz wykonać dla swoich plików.
no cóż, czy potok + nie readma takich samych problemów jak parsowanie ls? mianowicie, czyta wiersz po wierszu, więc nie działa w przypadku plików z
znakami
3
Masz rację. Moje poprzednie rozwiązanie nie działało w przypadku nazw plików zawierających nowe linie i prawdopodobnie przerwy w innych z określonymi znakami specjalnymi. Zaktualizowałem moją odpowiedź, aby używała zakończenia zerowego zamiast nowej linii.
scai
4
Jeśli masz zainstalowany Python (działa z Pythonem 2 lub Pythonem 3):
Aby wybrać jeden plik (lub wiersz z dowolnego polecenia), użyj
ls -1| python -c "import sys; import random; print(random.choice(sys.stdin.readlines()).rstrip())"
Aby wybrać Npliki / linie, użyj (uwaga Njest na końcu polecenia, zastąp to liczbą)
ls -1| python -c "import sys; import random; print(''.join(random.sample(sys.stdin.readlines(), int(sys.argv[1]))).rstrip())" N
To nie działa, jeśli nazwa pliku zawiera znaki nowej linii.
bfontaine
4
To jest jeszcze późniejsza odpowiedź na późną odpowiedź @ gniourf_gniourf, na którą właśnie głosowałem, ponieważ jest to zdecydowanie najlepsza odpowiedź, dwukrotnie. (Raz, aby uniknąć evali raz, aby bezpiecznie obsługiwać nazwy plików).
Ale zajęło mi kilka minut, aby rozplątać „niezbyt dobrze udokumentowane” funkcje, których używa ta odpowiedź. Jeśli twoje umiejętności Bash są na tyle solidne, że od razu zobaczyłeś, jak to działa, pomiń ten komentarz. Ale tego nie zrobiłem i po rozplątaniu tego uważam, że warto to wyjaśnić.
Cechą # 1 jest globalizacja plików własnej powłoki. a=(*)tworzy tablicę, $aktórej elementami są pliki w bieżącym katalogu. Bash rozumie wszystkie dziwactwa związane z nazwami plików, dzięki czemu lista jest poprawna, gwarantowana ucieczka itp. Nie musisz się martwić o poprawną analizę nazw plików tekstowych zwracanych przez ls.
Cechą nr 2 jest rozszerzenie parametrów Bash dla tablic , jedna zagnieżdżona w drugiej. Zaczyna się od ${#ARRAY[@]}, który rozwija się do długości $ARRAY.
To rozwinięcie jest następnie używane do indeksowania tablicy. Standardowym sposobem znalezienia liczby losowej z przedziału od 1 do N jest przyjęcie wartości liczby losowej modulo N. Chcemy uzyskać liczbę losową z przedziału od 0 do długości naszej tablicy. Oto podejście, dla jasności podzielone na dwie linie:
LENGTH=${#ARRAY[@]}
RANDOM=${a[RANDOM%$LENGTH]}
Ale to rozwiązanie robi to w jednym wierszu, eliminując niepotrzebne przypisywanie zmiennych.
Cechą # 3 jest rozszerzenie klamry Bash , chociaż muszę przyznać, że nie do końca to rozumiem. Interpretacja nawiasów jest używany, na przykład, aby wygenerować listę 25 plików nazwanych filename1.txt, filename2.txtitp: echo "filename"{1..25}".txt".
Wyrażenie wewnątrz podpowłoki powyżej, "${a[RANDOM%${#a[@]}]"{1..42}"}"używa tej sztuczki do stworzenia 42 oddzielnych ekspansji. Rozwinięcie nawiasów klamrowych umieszcza pojedynczą cyfrę między znakami ]i }, co na początku myślałem, że indeksuje tablicę, ale jeśli tak, byłoby poprzedzone dwukropkiem. (Zwróciłoby to również 42 kolejne elementy z losowego miejsca w tablicy, co wcale nie jest tym samym, co zwrócenie 42 losowych elementów z tablicy.) Myślę, że powoduje to po prostu wykonanie przez powłokę rozszerzenia 42 razy, zwracając w ten sposób 42 losowe pozycje z tablicy. (Ale jeśli ktoś może to wyjaśnić dokładniej, z przyjemnością to usłyszę.)
Powodem, dla którego N musi być zakodowane na stałe (do 42) jest to, że rozwijanie nawiasów klamrowych następuje przed rozwinięciem zmiennych.
Na koniec funkcja nr 4 , jeśli chcesz to zrobić rekurencyjnie dla hierarchii katalogów:
shopt -s globstar
a=(**)
Włącza to opcję powłoki, która powoduje **rekursywne dopasowywanie. Teraz twoja $atablica zawiera każdy plik w całej hierarchii.
#!/bin/bash# Reads a given directory and picks a random file.# The directory you want to use. You could use "$1" instead if you# wanted to parametrize it.
DIR="/path/to/"# DIR="$1"# Internal Field Separator set to newline, so file names with# spaces do not break our script.
IFS='
'if[[-d "${DIR}"]]then# Runs ls on the given dir, and dumps the output into a matrix,# it uses the new lines character as a field delimiter, as explained above.# file_matrix=($(ls -LR "${DIR}"))
file_matrix=($(ls -R $DIR | awk '; /:$/&&f{s=$0;f=0}; /:$/&&!f{sub(/:$/,"");s=$0;f=1;next}; NF&&f{ print s"/"$0 }'))
num_files=${#file_matrix[*]}# This is the command you want to run on a random file.# Change "ls -l" by anything you want, it's just an example.
ls -l "${file_matrix[$((RANDOM%num_files))]}"fi
exit 0
MacOS nie ma poleceń sort -R i shuf , więc potrzebowałem rozwiązania tylko dla basha, które losuje wszystkie pliki bez duplikatów i nie znalazłem tego tutaj. To rozwiązanie jest podobne do rozwiązania # 4 gniourf_gniourf, ale miejmy nadzieję, że dodaje lepsze komentarze.
Skrypt powinien być łatwy do zmodyfikowania i zatrzymania po N próbkach przy użyciu licznika z pętlą if lub gniourf_gniourf z N. $ RANDOM jest ograniczone do ~ 32000 plików, ale powinno to wystarczyć w większości przypadków.
#!/bin/bash
array=(*)# this is the array of files to shuffle# echo ${array[@]}for dummy in"${array[@]}";do# do loop length(array) times; once for each file
length=${#array[@]}
randomi=$(( $RANDOM % $length ))# select a random index
filename=${array[$randomi]}
echo "Processing: '$filename'"# do something with the file
unset -v "array[$randomi]"# set the element at index $randomi to NULL
array=("${array[@]}")# remove NULL elements introduced by unset; copy arraydone
ls | shuf -n 5
Źródło z Unix StackexchangeOdpowiedzi:
Oto skrypt, który używa opcji losowej GNU sort:
źródło
"$file"
, nie pokazane, byłoby wrażliwe na spacje.ls
?Możesz do tego użyć
shuf
(z pakietu GNU coreutils). Po prostu podaj listę nazw plików i poproś o zwrócenie pierwszej linii z losowej permutacji:Dostosuj
-n, --head-count=COUNT
wartość, aby zwrócić liczbę żądanych wierszy. Na przykład, aby zwrócić 5 losowych nazw plików, których użyłbyś:źródło
N
losowe pliki, więc użycie1
jest nieco mylące.find dirname -type f -print0 | shuf -zn1
Oto kilka możliwości, które nie analizują wyniku programu
ls
i są w 100% bezpieczne w przypadku plików ze spacjami i zabawnymi symbolami w nazwie. Wszystkie z nich wypełnią tablicęrandf
listą losowych plików. Wprintf '%s\n' "${randf[@]}"
razie potrzeby tablicę tę można łatwo wydrukować .Ten prawdopodobnie wyprowadzi ten sam plik kilka razy i
N
musi być znany z wyprzedzeniem. Tutaj wybrałem N = 42.Ta funkcja nie jest dobrze udokumentowana.
Jeśli N nie jest znane z góry, ale bardzo podobała Ci się poprzednia możliwość, możesz użyć
eval
. Ale to jest złe i naprawdę musisz się upewnić, żeN
nie pochodzi bezpośrednio z danych wejściowych użytkownika bez dokładnego sprawdzenia!Osobiście nie lubię
eval
i stąd ta odpowiedź!To samo przy użyciu prostszej metody (pętla):
Jeśli nie chcesz mieć kilkukrotnie tego samego pliku:
Uwaga . To jest późna odpowiedź na stary post, ale zaakceptowana odpowiedź prowadzi do zewnętrznej strony, która pokazuje okropnegrzmotnąćpraktyki, a druga odpowiedź nie jest dużo lepsza, ponieważ analizuje również wynik
ls
. Komentarz do zaakceptowanej odpowiedzi wskazuje na doskonałą odpowiedź Lhunatha, która oczywiście pokazuje dobrą praktykę, ale nie odpowiada dokładnie PO.źródło
"{1..42}"
część pozostawia ślad"1"
. Ponadto$RANDOM
jest tylko 15-bitowy, a metoda nie będzie działać z ponad 32767 plikami do wyboru.źródło
ls
. To nie zadziała, jeśli np. Nazwa pliku zawiera znaki nowej linii.ls
nie gwarantuje, że podasz "czyste" nazwy plików, więc nie powinieneś na tym polegać. Fakt, że te problemy są rzadkie lub niezwykłe, nie zmienia problemu; zwłaszcza biorąc pod uwagę, że istnieją lepsze rozwiązania tego problemu.ls
może zawierać katalogi i puste wiersze.find . -type f | shuf -n10
Zamiast tego sugerowałbym coś takiego .Proste rozwiązanie do wybierania
5
losowych plików bez analizowania ls . Działa również z plikami zawierającymi spacje, znaki nowej linii i inne znaki specjalne:Zastąp
echo
polecenie, które chcesz wykonać dla swoich plików.źródło
read
ma takich samych problemów jak parsowaniels
? mianowicie, czyta wiersz po wierszu, więc nie działa w przypadku plików zJeśli masz zainstalowany Python (działa z Pythonem 2 lub Pythonem 3):
Aby wybrać jeden plik (lub wiersz z dowolnego polecenia), użyj
Aby wybrać
N
pliki / linie, użyj (uwagaN
jest na końcu polecenia, zastąp to liczbą)źródło
To jest jeszcze późniejsza odpowiedź na późną odpowiedź @ gniourf_gniourf, na którą właśnie głosowałem, ponieważ jest to zdecydowanie najlepsza odpowiedź, dwukrotnie. (Raz, aby uniknąć
eval
i raz, aby bezpiecznie obsługiwać nazwy plików).Ale zajęło mi kilka minut, aby rozplątać „niezbyt dobrze udokumentowane” funkcje, których używa ta odpowiedź. Jeśli twoje umiejętności Bash są na tyle solidne, że od razu zobaczyłeś, jak to działa, pomiń ten komentarz. Ale tego nie zrobiłem i po rozplątaniu tego uważam, że warto to wyjaśnić.
Cechą # 1 jest globalizacja plików własnej powłoki.
a=(*)
tworzy tablicę,$a
której elementami są pliki w bieżącym katalogu. Bash rozumie wszystkie dziwactwa związane z nazwami plików, dzięki czemu lista jest poprawna, gwarantowana ucieczka itp. Nie musisz się martwić o poprawną analizę nazw plików tekstowych zwracanych przezls
.Cechą nr 2 jest rozszerzenie parametrów Bash dla tablic , jedna zagnieżdżona w drugiej. Zaczyna się od
${#ARRAY[@]}
, który rozwija się do długości$ARRAY
.To rozwinięcie jest następnie używane do indeksowania tablicy. Standardowym sposobem znalezienia liczby losowej z przedziału od 1 do N jest przyjęcie wartości liczby losowej modulo N. Chcemy uzyskać liczbę losową z przedziału od 0 do długości naszej tablicy. Oto podejście, dla jasności podzielone na dwie linie:
Ale to rozwiązanie robi to w jednym wierszu, eliminując niepotrzebne przypisywanie zmiennych.
Cechą # 3 jest rozszerzenie klamry Bash , chociaż muszę przyznać, że nie do końca to rozumiem. Interpretacja nawiasów jest używany, na przykład, aby wygenerować listę 25 plików nazwanych
filename1.txt
,filename2.txt
itp:echo "filename"{1..25}".txt"
.Wyrażenie wewnątrz podpowłoki powyżej,
"${a[RANDOM%${#a[@]}]"{1..42}"}"
używa tej sztuczki do stworzenia 42 oddzielnych ekspansji. Rozwinięcie nawiasów klamrowych umieszcza pojedynczą cyfrę między znakami]
i}
, co na początku myślałem, że indeksuje tablicę, ale jeśli tak, byłoby poprzedzone dwukropkiem. (Zwróciłoby to również 42 kolejne elementy z losowego miejsca w tablicy, co wcale nie jest tym samym, co zwrócenie 42 losowych elementów z tablicy.) Myślę, że powoduje to po prostu wykonanie przez powłokę rozszerzenia 42 razy, zwracając w ten sposób 42 losowe pozycje z tablicy. (Ale jeśli ktoś może to wyjaśnić dokładniej, z przyjemnością to usłyszę.)Powodem, dla którego N musi być zakodowane na stałe (do 42) jest to, że rozwijanie nawiasów klamrowych następuje przed rozwinięciem zmiennych.
Na koniec funkcja nr 4 , jeśli chcesz to zrobić rekurencyjnie dla hierarchii katalogów:
Włącza to opcję powłoki, która powoduje
**
rekursywne dopasowywanie. Teraz twoja$a
tablica zawiera każdy plik w całej hierarchii.źródło
Jeśli masz więcej plików w swoim folderze, możesz użyć poniższego polecenia potokowego, które znalazłem w unix stackexchange .
Tutaj chciałem skopiować pliki, ale jeśli chcesz przenieść pliki lub zrobić coś innego, po prostu zmień ostatnie polecenie, w którym użyłem
cp
.źródło
To jedyny skrypt, który mogę dobrze zagrać w bash na MacOS. Połączyłem i zredagowałem fragmenty z następujących dwóch linków:
Polecenie ls: jak mogę uzyskać rekurencyjną listę pełnej ścieżki, po jednej linii na plik?
http://www.linuxquestions.org/questions/linux-general-1/is-there-a-bash-command-for-picking-a-random-file-678687/
źródło
MacOS nie ma poleceń sort -R i shuf , więc potrzebowałem rozwiązania tylko dla basha, które losuje wszystkie pliki bez duplikatów i nie znalazłem tego tutaj. To rozwiązanie jest podobne do rozwiązania # 4 gniourf_gniourf, ale miejmy nadzieję, że dodaje lepsze komentarze.
Skrypt powinien być łatwy do zmodyfikowania i zatrzymania po N próbkach przy użyciu licznika z pętlą if lub gniourf_gniourf z N. $ RANDOM jest ograniczone do ~ 32000 plików, ale powinno to wystarczyć w większości przypadków.
źródło
Używam tego: używa pliku tymczasowego, ale wnika głęboko w katalog, dopóki nie znajdzie zwykłego pliku i nie zwróci go.
źródło
A co z rozwiązaniem w Perlu, które nieco przerobił pan Kang tutaj:
Jak mogę przetasować wiersze w pliku tekstowym w linii poleceń Unixa lub w skrypcie powłoki?
źródło