Bagaimana cara mengacak baris dalam file menggunakan alat standar di Red Hat Linux?

102

Bagaimana cara mengacak baris dalam file menggunakan alat standar di Red Hat Linux?

Saya tidak memiliki shufperintah, jadi saya mencari sesuatu seperti perlatau awksatu baris yang menyelesaikan tugas yang sama.

Stuart Woodward
sumber
1
Saya menanyakan pertanyaan yang hampir sama [ stackoverflow.com/questions/286640/…
Steve Schnepp
Saya menganggap gcc sebagai alat standar di linux mana pun. ; D
msb

Jawaban:

64

Dan Anda mendapatkan Perl one-liner!

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

Ini menggunakan modul, tetapi modul tersebut adalah bagian dari distribusi kode Perl. Jika itu tidak cukup baik, Anda dapat mempertimbangkan untuk menggulungnya sendiri.

Saya mencoba menggunakan ini dengan -ibendera ("edit-in-place") untuk mengedit file. Dokumentasi menyarankan itu harus berfungsi, tetapi tidak. Ini masih menampilkan file yang diacak ke stdout, tapi kali ini menghapus aslinya. Saya sarankan Anda tidak menggunakannya.

Pertimbangkan skrip shell:

#!/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

Belum teruji, tapi semoga berhasil.

Chris Lutz
sumber
Untuk mencadangkan file asli, Anda dapat mencadangkan ekstensi ke bendera -i [ perldoc.perl.org/perlrun.html]
Steve
Saya biasanya penggemar Perl, tapi datang di contoh ruby ini yang memiliki manfaat yang lebih pendek: ruby -e 'puts STDIN.readlines.shuffle'. Diperlukan pengujian pada input besar untuk melihat apakah kecepatannya sebanding. (juga bekerja pada OS X)
mivk
per komentar di bawah, shufmemuat semuanya ke dalam memori, sehingga tidak berfungsi dengan file yang benar-benar besar (milik saya ~ 300GB tsv). Skrip perl ini juga gagal pada saya, tetapi tanpa kesalahan kecuali Killed. Adakah ide jika solusi perl memuat semuanya ke dalam memori juga, atau adakah masalah lain yang saya hadapi?
seth127
211

Um, jangan lupa

sort --random-sort
Jim T
sumber
1
Saya menggunakan gnu-coreutils 7.1 (instalasi gentoo standar), yang memiliki sort dengan opsi ini, tidak yakin kapan muncul, atau apakah itu dalam implementasi lain.
Jim T
1
Fitur ini dibuat pada tanggal 10 Desember 2005, rilis berikutnya adalah 5.94, jadi saya rasa itu sudah tersedia sejak versi itu.
Jim T
41
Di OS X Anda dapat menginstal gnu coreutils dengan homebrew: brew install coreutilsSemua utilitas diawali dengan ag jadi: gsort --random-sortatau gshufakan berfungsi seperti yang diharapkan
mike
3
+1 @ mike. Saya menggunakan Macports dan saya juga memiliki gsortdan gshufmenginstal ketika saya melakukannyaport install coreutils
Noah Sussman
10
Solusi ini hanya bagus jika baris Anda tidak memiliki pengulangan. Jika ya, semua contoh dari baris itu akan muncul bersebelahan. Pertimbangkan untuk menggunakan shufsebagai gantinya (di linux).
Ali J
118

shuf adalah cara terbaik.

sort -Rsangat lambat. Saya hanya mencoba mengurutkan file 5GB. Saya menyerah setelah 2,5 jam. Kemudian shufdiurutkan dalam satu menit.

Michal Illich
sumber
Ini bagus. Tampaknya dalam coreutils GNU.
ariddell
4
Saya menduga alasannya sort -Rlambat adalah karena menghitung hash untuk setiap baris. Dari dokumen: " Urutkan menurut hashing kunci input dan kemudian urutkan nilai hash. "
Joe Flynn
13
berhati-hatilah, shufmuat semuanya di memori.
jfs
1
@benroth: Dari apa yang saya tahu, dengan jumlah masukan benar-benar besar meningkatkan memori dapat membantu agak , tapi masih lambat secara keseluruhan. Dalam pengujian saya, menyortir file input 1 juta baris yang dibuat dengan seq -f 'line %.0f' 1000000memakan waktu yang sama dan lama untuk diproses (jauh, lebih lama daripada dengan shuf), tidak peduli berapa banyak memori yang saya alokasikan.
mklement0
1
@ mklement0, Anda benar! Saya baru saja mencobanya dengan file yang jauh lebih besar dari yang saya miliki sebelumnya, dan hashing tampaknya memang menjadi penghambat.
benroth
23
cat yourfile.txt | while IFS= read -r f; do printf "%05d %s\n" "$RANDOM" "$f"; done | sort -n | cut -c7-

Baca file, tambahkan setiap baris dengan nomor acak, urutkan file pada awalan acak tersebut, potong awalan setelahnya. Satu baris yang seharusnya berfungsi di shell semi-modern.

EDIT: memasukkan pernyataan Richard Hansen.

ChristopheD
sumber
1
Ini berfungsi, dan merupakan solusi kreatif, tetapi akan menghapus spasi kosong di baris.
Chris Lutz
@Chris mengubah potongan terakhir menjadi | sed 's / ^ [^ \ t] * \ t //' harus memperbaikinya
bdonlan
Kudos untuk kesederhanaan pendekatannya!
Shashikant Kore
3
+1 untuk kesesuaian POSIX (kecuali untuk $RANDOM), tetapi -1 untuk memotong data. Mengganti while read fdengan while IFS= read -r fakan mencegah readpenghapusan spasi kosong di depan dan di belakang (lihat jawaban ini ) dan mencegah pemrosesan garis miring terbalik. Menggunakan string acak dengan panjang tetap akan mencegah cutpenghapusan spasi kosong di depan. Hasil: 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: Terima kasih, perubahan yang disarankan ini jelas sesuai, saya telah mengedit posting saya.
ChristopheD
9

Satu baris untuk python:

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

Dan untuk mencetak hanya satu baris acak:

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

Tapi lihat posting ini untuk kekurangan python random.shuffle(). Ini tidak akan bekerja dengan baik dengan banyak (lebih dari 2080) elemen.

scai
sumber
5

Terkait dengan jawaban Jim:

Saya ~/.bashrcberisi yang berikut:

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

Dengan GNU coreutils's sort, -R= --random-sort, yang menghasilkan hash acak dari setiap baris dan mengurutkannya. Hash acak tidak akan benar-benar digunakan di beberapa lokal di beberapa versi yang lebih lama (buggy), menyebabkannya mengembalikan output yang diurutkan normal, itulah sebabnya saya menetapkan LC_ALL=C.


Terkait dengan jawaban Chris:

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

adalah satu baris yang sedikit lebih pendek. ( -Mmodule=a,b,cadalah singkatan dari -e 'use module qw(a b c);'.)

Alasan memberikannya sederhana -itidak berfungsi untuk pengacakan di tempat adalah karena Perl mengharapkan bahwa printterjadi di loop yang sama file sedang dibaca, dan print shuffle <>tidak keluar sampai setelah semua file input telah dibaca dan ditutup.

Sebagai solusi yang lebih singkat,

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

akan mengacak file di tempat. ( -nartinya "membungkus kode dalam satu while (<>) {...}lingkaran; BEGIN{undef$/}membuat Perl beroperasi pada file-at-a-time alih-alih baris-pada-waktu, dan split/^/mdiperlukan karena $_=<>telah dilakukan secara implisit dengan seluruh file, bukan baris.)

singkat
sumber
Mengulangi semacam itu -R tidak ada di OS X, tetapi +1 untuk beberapa jawaban Perl yang bagus, dan jawaban yang bagus secara umum.
Chris Lutz
Anda dapat menginstal GNU coreutils di OS X, tetapi (seperti yang telah saya lakukan di masa lalu) Anda harus berhati-hati untuk tidak merusak alat bawaan ... Meskipun demikian, OP ada di Redhat Linux, yang pasti memiliki GNU standar coreutils.
singkat
3

Ketika saya menginstal coreutils dengan homebrew

brew install coreutils

shufmenjadi tersedia sebagai n.

John McDonnell
sumber
minuman diawali semua perintah dengan gbegitu shufmenjadi gshufbagi saya.
Jörn
^ Apakah itu karena mereka non-POSIX, atau apakah saya benar-benar tidak aktif?
Dave Liu
1

Mac OS X dengan DarwinPorts:

sudo port install unsort
cat $file | unsort | ...
Coroos
sumber
1

FreeBSD memiliki utilitas acaknya sendiri:

cat $file | random | ...

Ada di / usr / games / random, jadi jika Anda belum menginstal game, Anda kurang beruntung.

Anda dapat mempertimbangkan untuk menginstal port seperti textproc / rand atau textproc / msort. Ini mungkin tersedia di Linux dan / atau Mac OS X, jika portabilitas menjadi perhatian.

Coroos
sumber
-1

Di OSX, ambil yang terbaru dari http://ftp.gnu.org/gnu/coreutils/ dan semacamnya

./configure make sudo make install

... harus memberi Anda / usr / local / bin / sort --random-sort

tanpa mengacaukan / usr / bin / sort

Dan Brickley
sumber
ini tidak berhasil untuk saya di OSX (10.7). Saya mendapat "configure: error: compiler C tidak dapat membuat executable".
Dolan Antenucci
@dolan Periksa izin Anda?
Benubird
-1

Atau dapatkan dari MacPorts:

$ sudo port install coreutils

dan / atau

$ /opt/local//libexec/gnubin/sort --random-sort
Chadwick Boggs
sumber