Bir metin dosyasının satırlarını rastgele karıştırmak ve yeni bir dosya oluşturmak istiyorum. Dosyada binlerce satır olabilir.
Nasıl ile yapabilirsiniz cat, awk, cut, vs?
Bir metin dosyasının satırlarını rastgele karıştırmak ve yeni bir dosya oluşturmak istiyorum. Dosyada binlerce satır olabilir.
Nasıl ile yapabilirsiniz cat, awk, cut, vs?
Yanıtlar:
Kullanabilirsiniz shuf. Bazı sistemlerde en azından (POSIX'te görünmüyor).
Jleedev'in işaret ettiği gibi: sort -Rbir seçenek de olabilir. Bazı sistemlerde en azından; resim elde edersiniz. Bu sivri dışarı olmuştursort -R gerçekten karıştırmak yerine sıralama öğeler onların karma değerine göre değil.
[Editörün notu: yinelenen satırlar / sıralama anahtarlarının her zaman yan yana olması dışında sort -R neredeyse karışır . Başka bir deyişle: sadece benzersiz giriş satırları / tuşları ile gerçek bir karışıklıktır. Çıktı sırasının hash değerleri tarafından belirlendiği doğru olsa da , rastgelelik rastgele bir hash fonksiyonu seçmekten gelir - kılavuza bakınız .]
shufve sort -Rnedeni, biraz farklıdır sort -Rrastgele emir elemanları uygun karma bir tanesi, sort -Rbirbirine tekrarlandı elemanları koymak shufrastgele karıştırır tüm elemanları.
brew install coreutilssonra şunu kullanın gshuf ...: (:
sort -Rve shuftamamen farklı görülmelidir. sort -Rbelirleyicidir. Aynı girişte farklı zamanlarda iki kez çağırırsanız aynı cevabı alırsınız. shufÖte yandan, rastgele çıktı üretir, bu nedenle büyük olasılıkla aynı girdi üzerinde farklı çıktılar verir.
Perl tek astar, Maxim'in çözümünün basit bir versiyonu olacaktır
perl -MList::Util=shuffle -e 'print shuffle(<STDIN>);' < myfile
\n; evet, bu \nmevcut olmalı - ve tipik olarak - aksi takdirde tarif ettiğiniz şeyi alırsınız.
<STDIN>ile <>çözüm girişi ile çalışır, böylece dosyaları da.
Bu cevap mevcut birçok harika yanıtı aşağıdaki şekillerde tamamlar:
Mevcut cevaplar esnek kabuk fonksiyonlarında paketlenmiştir :
stdingirdi değil , aynı zamanda dosya adı argümanlarını da alırSIGPIPE141 . Bu, fonksiyon çıkışını, boruları döşerken olduğu gibi erken kapalı bir boruya bağlarken önemlidir head.Bir performans karşılaştırması yapılır.
awk, sortvecut , uyarlanan OP'ın kendi cevap :shuf() { awk 'BEGIN {srand(); OFMT="%.17f"} {print rand(), $0}' "$@" |
sort -k1,1n | cut -d ' ' -f2-; }
shuf() { perl -MList::Util=shuffle -e 'print shuffle(<>);' "$@"; }
shuf() { python -c '
import sys, random, fileinput; from signal import signal, SIGPIPE, SIG_DFL;
signal(SIGPIPE, SIG_DFL); lines=[line for line in fileinput.input()];
random.shuffle(lines); sys.stdout.write("".join(lines))
' "$@"; }
Bu işlevin Windows sürümü için alt bölüme bakın .
shuf() { ruby -e 'Signal.trap("SIGPIPE", "SYSTEM_DEFAULT");
puts ARGF.readlines.shuffle' "$@"; }
Performans karşılaştırması:
Not: Bu sayılar, 3.2 GHz Intel Core i5 ve OSX 10.10.3 çalıştıran bir Fusion Drive'a sahip 2012 sonlarında iMac'te elde edildi. Zamanlamalar kullanılan işletim sistemine, makine özelliklerine, awkkullanılan uygulamaya (ör awk. OSX'te kullanılan BSD sürümü genellikle GNU'dan daha yavaştır awkve özellikle mawk) göre değişmekle birlikte , bu genel bir göreceli performans duygusu sağlamalıdır .
Girdi dosyası ile üretilen 1 milyon satırlık bir dosyadırseq -f 'line %.0f' 1000000 .
Zamanlar artan sırada listelenir (en hızlısı önce):
shuf
0.090s0.289s0.589s1.342sPython 2.7.6 ile; 2.407s(!) Python 3.4.2 ileawk+ sort+cut
3.003sBSD ile awk; 2.388sGNU awk(4.1.1) ile; 1.811sile mawk(1.3.4);Daha fazla karşılaştırma için, yukarıdaki fonksiyonlar olarak paketlenmemiş çözümler:
sort -R (yinelenen giriş satırları varsa gerçek bir karıştırma değil)
10.661s - daha fazla bellek ayırmanın bir fark yarattığı görülmüyor24.229sbash döngüler + sort
32.593sSonuç :
shuf, eğer yapabilirsen - açık arayla en hızlı.awk+ sort+ cutcombo'yu son çare olarak kullanın ; hangi awkuygulamayı kullandığınız önemlidir ( GNU'dan mawkdaha hızlı awk, BSD awken yavaştır).sort -R, bashdöngüler ve Scala.Python çözümünün Windows sürümleri (Python kodu, Windows'ta desteklenmeyen tırnak işaretleri ve sinyalle ilgili ifadelerin kaldırılması hariç) aynıdır:
$OutputEncodingASCII olmayan karakterleri ardışık düzen yoluyla göndermek isteyip istemediğinizi ayarlamanız gerekir ):# Call as `shuf someFile.txt` or `Get-Content someFile.txt | shuf`
function shuf {
$Input | python -c @'
import sys, random, fileinput;
lines=[line for line in fileinput.input()];
random.shuffle(lines); sys.stdout.write(''.join(lines))
'@ $args
}
PowerShell'in Get-Randomcmdlet'i aracılığıyla yerel olarak karışabileceğini unutmayın (performans bir sorun olabilir); Örneğin:
Get-Content someFile.txt | Get-Random -Count ([int]::MaxValue)
cmd.exe(toplu iş dosyası):Dosyaya kaydet shuf.cmd, örneğin:
@echo off
python -c "import sys, random, fileinput; lines=[line for line in fileinput.input()]; random.shuffle(lines); sys.stdout.write(''.join(lines))" %*
python -c "import sys, random; lines = [x for x in sys.stdin.read().splitlines()] ; random.shuffle(lines); print(\"\n\".join([line for line in lines]));"
from signal import signal, SIGPIPE, SIG_DFL; signal(SIGPIPE, SIG_DFL);orijinal çözümden atlamak yeterlidir ve dosya adı argümanlarını da geçirme esnekliğini korur - başka bir şeyi değiştirmeye gerek yoktur (alıntı dışında) - lütfen eklediğim yeni bölüme bakın alt.
Ben "unsort" dediğim küçük bir perl betiği kullanın:
#!/usr/bin/perl
use List::Util 'shuffle';
@list = <STDIN>;
print shuffle(@list);
Ayrıca find -print0 ve benzeri ile kullanmak için kullanışlı "unsort0" adlı bir NULL sınırlandırılmış sürümü var.
Not: Ben de 'shuf' seçtim, bugünlerde coreutils orada olduğunu bilmiyordum ... sistemleriniz 'shuf' yoksa yukarıdakiler yine de yararlı olabilir.
<STDIN>ile değiştirmenizi öneririm . <>
Burada, kodlayıcıda kolay olan ancak her satıra rasgele bir sayı ekleyen, sıralayan ve daha sonra rasgele sayıyı her satırdan ayıran CPU üzerinde zor olan bir ilk deneme var. Aslında, çizgiler rastgele sıralanır:
cat myfile | awk 'BEGIN{srand();}{print rand()"\t"$0}' | sort -k1 -n | cut -f2- > myfile.shuffled
head myfile | awk .... Sonra onu kedi olarak değiştiriyorum; bu yüzden orada kaldı.
-k1 -nSıralamaya gerek yok , çünkü awk'ın çıktısı rand()0 ile 1 arasında bir ondalık sayıdır ve tek önemli olan şey bir şekilde yeniden sıralanmasıdır. -k1rand () çıktısının karşılaştırmayı kısa devre yapacak kadar benzersiz olması gerekirken, hattın geri kalanını yoksayarak hızlanmasına yardımcı olabilir.
cat filename |(veya < filename |) saklamak daha iyidir.
işte garip bir senaryo
awk 'BEGIN{srand() }
{ lines[++d]=$0 }
END{
while (1){
if (e==d) {break}
RANDOM = int(1 + rand() * d)
if ( RANDOM in lines ){
print lines[RANDOM]
delete lines[RANDOM]
++e
}
}
}' file
çıktı
$ cat file
1
2
3
4
5
6
7
8
9
10
$ ./shell.sh
7
5
10
9
6
8
2
1
3
4
awkile birleşen kendi cevabından çok daha yavaştır . Birkaç binden fazla satır için çok fazla bir fark yaratmaz, ancak daha yüksek satır sayıları ile önemlidir (eşik kullanılan uygulamaya bağlıdır ). Çizgileri değiştirmek ve ile hafif bir sadeleştirme olacaktır . sortcutawkwhile (1){if (e==d) {break}while (e<d)
Python için bir astar:
python -c "import random, sys; lines = open(sys.argv[1]).readlines(); random.shuffle(lines); print ''.join(lines)," myFile
Ve sadece tek bir rastgele çizgi yazdırmak için:
python -c "import random, sys; print random.choice(open(sys.argv[1]).readlines())," myFile
Ama bakın bu yazı piton en dezavantajlarından için random.shuffle(). Birçok (2080'den fazla) elemanla iyi çalışmaz.
/dev/urandom. Python onu kullanmak için: random.SystemRandom().shuffle(L).
.readLines()geri dönüş hatları ile bir arka yeni satır.
Basit awk tabanlı işlev işi yapacak:
shuffle() {
awk 'BEGIN{srand();} {printf "%06d %s\n", rand()*1000000, $0;}' | sort -n | cut -c8-
}
kullanımı:
any_command | shuffle
Bu hemen hemen her UNIX üzerinde çalışmalıdır. Linux, Solaris ve HP-UX üzerinde test edilmiştir.
Güncelleme:
Baştaki sıfırların ( %06d) ve rand()çarpma işleminin sortsayıları anlamayan sistemlerde de düzgün çalışmasını sağladığını unutmayın. Sözcük bilgisi sırasına göre sıralanabilir (normal dize karşılaştırması olarak da bilinir).
"$@", girdi olarak dosyalarla da çalışır . Çoğalmak için bir neden yoktur rand(), çünkü sort -nondalık kesirleri sıralayabilir. Bununla beraber, kontrol etmek için iyi bir fikirdir awk, çünkü varsayılan biçim, ile, 'ın çıkış biçimi %.6g, rand()irade çıkışı ara sıra numarası üstel gösterimde. Uygulamada 1 milyon satıra kadar karıştırmak muhtemelen yeterli olsa da, bir performans cezası ödemeden daha fazla satırı desteklemek kolaydır; örn %.17f.
sortondalık kesirleri işleyebilmelidir (az önce fark ettiğim gibi binlerce ayırıcıyla bile).
Yakut FTW:
ls | ruby -e 'puts STDIN.readlines.shuffle'
puts ARGF.readlines.shuffle, bunun hem standart girdinin girdi ve dosya adı argümanları ile çalışmak yapabilirsiniz.
ruby -e 'puts $<.sort_by{rand}'- ARGF zaten numaralandırılabilir, bu nedenle çizgileri rastgele değerlere göre sıralayarak karıştırabiliriz.
Python için scai'nin cevabına dayanan bir astar , ancak a) stdin alır, b) sonucu tohumla tekrarlanabilir hale getirir, c) tüm hatların sadece 200'ünü alır.
$ cat file | python -c "import random, sys;
random.seed(100); print ''.join(random.sample(sys.stdin.readlines(), 200))," \
> 200lines.txt
Kullanmanın basit ve sezgisel bir yolu olurdu shuf.
Misal:
Varsayın words.txt:
the
an
linux
ubuntu
life
good
breeze
Çizgileri karıştırmak için şunları yapın:
$ shuf words.txt
karıştırılan çizgileri standart çıktıya atar ; Yani, hiç ettik borusuna bir karşı kendisine çıkış dosyası gibi:
$ shuf words.txt > shuffled_words.txt
Böyle bir karıştırma çalıştırması aşağıdakileri verebilir:
breeze
the
linux
an
ubuntu
good
life
Bu, ana klasörümde rand.py olarak kaydettiğim bir python betiği:
#!/bin/python
import sys
import random
if __name__ == '__main__':
with open(sys.argv[1], 'r') as f:
flist = f.readlines()
random.shuffle(flist)
for line in flist:
print line.strip()
Mac OSX üzerinde sort -Rve shufsen gibi bash_profile bu diğer ad böylece kullanılamaz:
alias shuf='python rand.py'
Benim gibi buraya shufmacOS için alternatif aramak için geldiysenizrandomize-lines .
Benzer işleve randomize-linessahip bir rlkomutu olan Install (homebrew) paketi shuf.
brew install randomize-lines
Usage: rl [OPTION]... [FILE]...
Randomize the lines of a file (or stdin).
-c, --count=N select N lines from the file
-r, --reselect lines may be selected multiple times
-o, --output=FILE
send output to file
-d, --delimiter=DELIM
specify line delimiter (one character)
-0, --null set line delimiter to null character
(useful with find -print0)
-n, --line-number
print line number with output lines
-q, --quiet, --silent
do not output any errors or warnings
-h, --help display this help and exit
-V, --version output version information and exit
brew install coreutilssağlar shufolarak ikili gshuf.
Scala yüklüyse, girişi karıştırmak için bir astar:
ls -1 | scala -e 'for (l <- util.Random.shuffle(io.Source.stdin.getLines.toList)) println(l)'
Bu bash işlevi minimum bağımlılığa sahiptir (yalnızca sıralama ve bash):
shuf() {
while read -r x;do
echo $RANDOM$'\x1f'$x
done | sort |
while IFS=$'\x1f' read -r x y;do
echo $y
done
}
awkdestekli çözümüne paralel olan güzel bash çözümü , ancak performans daha büyük girdilerle ilgili bir sorun olacaktır; tek bir $RANDOMdeğeri kullanmanız yalnızca 32.768 giriş satırına kadar doğru şekilde karıştırır; bu aralığı genişletebilmenize rağmen, muhtemelen buna değmez: örneğin, makinemde, komut dosyanızı 32.768 kısa giriş satırında çalıştırmak yaklaşık 1 saniye sürer, bu da çalışma süresinin yaklaşık 150 katı shufve yaklaşık 10-15 kez OP'nin kendi awkdestekli çözümü aldığı sürece. Güvenebileceğiniz ise sortvarlık mevcut, awkhem de orada olmalı.
Windows'da data.txt dosyanızı karıştırmanıza yardımcı olması için bu toplu iş dosyasını deneyebilirsiniz . Toplu iş kodunun kullanımı
C:\> type list.txt | shuffle.bat > maclist_temp.txt
Bu komutu verdikten sonra maclist_temp.txt rastgele bir satır listesi içerecektir.
Bu yardımcı olur umarım.
Henüz belirtilmemiş:
unsortUtil. Sözdizimi (bir şekilde oynatma listesine yönelik):
unsort [-hvrpncmMsz0l] [--help] [--version] [--random] [--heuristic]
[--identity] [--filenames[=profile]] [--separator sep] [--concatenate]
[--merge] [--merge-random] [--seed integer] [--zero-terminated] [--null]
[--linefeed] [file ...]msort satır satır karışabilir, ancak genellikle aşırıya kaçar:
seq 10 | msort -jq -b -l -n 1 -c r