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 -R
bir 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 .]
shuf
ve sort -R
nedeni, biraz farklıdır sort -R
rastgele emir elemanları uygun karma bir tanesi, sort -R
birbirine tekrarlandı elemanları koymak shuf
rastgele karıştırır tüm elemanları.
brew install coreutils
sonra şunu kullanın gshuf ...
: (:
sort -R
ve shuf
tamamen farklı görülmelidir. sort -R
belirleyicidir. 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 \n
mevcut 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 :
stdin
girdi değil , aynı zamanda dosya adı argümanlarını da alırSIGPIPE
141
. 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
, sort
vecut
, 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, awk
kullanılan uygulamaya (ör awk
. OSX'te kullanılan BSD sürümü genellikle GNU'dan daha yavaştır awk
ve ö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.090s
0.289s
0.589s
1.342s
Python 2.7.6 ile; 2.407s
(!) Python 3.4.2 ileawk
+ sort
+cut
3.003s
BSD ile awk
; 2.388s
GNU awk
(4.1.1) ile; 1.811s
ile 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.229s
bash
döngüler + sort
32.593s
Sonuç :
shuf
, eğer yapabilirsen - açık arayla en hızlı.awk
+ sort
+ cut
combo'yu son çare olarak kullanın ; hangi awk
uygulamayı kullandığınız önemlidir ( GNU'dan mawk
daha hızlı awk
, BSD awk
en yavaştır).sort -R
, bash
dö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:
$OutputEncoding
ASCII 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-Random
cmdlet'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 -n
Sı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. -k1
rand () çı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
awk
ile 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 . sort
cut
awk
while (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 sort
sayı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 -n
ondalı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
.
sort
ondalı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 -R
ve shuf
sen gibi bash_profile bu diğer ad böylece kullanılamaz:
alias shuf='python rand.py'
Benim gibi buraya shuf
macOS için alternatif aramak için geldiysenizrandomize-lines
.
Benzer işleve randomize-lines
sahip bir rl
komutu 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 coreutils
sağlar shuf
olarak 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
}
awk
destekli çözümüne paralel olan güzel bash çözümü , ancak performans daha büyük girdilerle ilgili bir sorun olacaktır; tek bir $RANDOM
değ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ı shuf
ve yaklaşık 10-15 kez OP'nin kendi awk
destekli çözümü aldığı sürece. Güvenebileceğiniz ise sort
varlık mevcut, awk
hem 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ş:
unsort
Util. 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