Saya mencoba menulis skrip shell. Idenya adalah untuk memilih satu baris secara acak dari file teks dan menampilkannya sebagai notifikasi desktop Ubuntu.
Tapi saya ingin baris yang berbeda dipilih setiap kali saya menjalankan skrip. Apakah ada solusi untuk melakukan ini? Saya tidak ingin seluruh skrip. Hanya hal sederhana itu saja.
scripts
text-processing
Anandu M Das
sumber
sumber
Jawaban:
Anda dapat menggunakan
shuf
utilitas untuk mencetak garis acak dari file-n
: jumlah garis untuk dicetakContoh:
sumber
n
menunjukkan jumlah baris yang akan dicetak. (Yaitu apakah Anda ingin hanya satu baris atau dua baris). Bukan nomor baris (yaitu baris kedua baris pertama).date +%S
) ke dalam variabel x, dan kemudian memilih baris ke-X menggunakan perintahhead
dantail
dari file teks. Bagaimanapun metode Anda lebih mudah. Terima kasihshuf
ada di coreutils sehingga tersedia secara default. Catatan: ini memuat file input ke dalam memori. Ada algoritma efisien yang tidak memerlukannya .Anda juga dapat menggunakan
sort
perintah untuk mendapatkan garis acak dari file.sumber
sort -R
menghasilkan hasil yang berbeda darishuf -n1
atauselect-random
jika ada garis duplikat di input. Lihat komentar @ EliahKagan .Just for fun, di sini adalah solusi pesta murni yang tidak menggunakan
shuf
,sort
,wc
,sed
,head
,tail
atau alat eksternal lainnya.Satu-satunya keunggulan dibandingkan
shuf
varian adalah sedikit lebih cepat, karena ini murni bash. Di komputer saya, untuk file 1000 baris,shuf
varian membutuhkan waktu sekitar 0,1 detik, sedangkan skrip berikut membutuhkan waktu sekitar 0,01 detik;) Jadi, sementara itushuf
adalah varian termudah dan terpendek, ini lebih cepat.Dalam semua kejujuran saya masih akan mencari
shuf
solusinya, kecuali efisiensi tinggi adalah masalah penting.sumber
shuf
pula, menggunakan jauh lebih baik. Memikirkan itu, saya tidak percaya bahwa bash murni sebenarnya lebih efisien daripada menggunakanshuf
, seperti yang saya tulis sebelumnya. Mungkin ada overhead terkecil (konstan) ketika menjalankan alat eksternal, tetapi kemudian itu akan menjalankan mach lebih cepat daripada bash yang ditafsirkan. Jadishuf
tentu saja skala lebih baik. Jadi, katakanlah skrip tersebut memiliki tujuan pendidikan: Senang rasanya bisa dilakukan;)shuf
GNU Coreutils - spesifik (mis. Tidak dalam FreeBSD 10.0).sort -R
bersifat portabel, tetapi memecahkan masalah (terkait) yang berbeda: string yang muncul karena beberapa baris memiliki probabilitas yang sama dengan yang muncul hanya sekali. (Tentu saja,wc
dan utilitas lain masih dapat digunakan.) Saya pikir batasan utama di sini adalah ini tidak pernah mengambil apa pun setelah garis 32768 (dan menjadi kurang acak agak cepat).$((RANDOM<<15|RANDOM))
ada di 0..2 ^ 30-1. @ JSFSebastian Bukanshuf
, inisort -R
condong ke input yang lebih sering. Masukanshuf -n 1
di tempatsort -R | head -n1
dan membandingkan. (Btw 10 ^ 3 iterasi lebih cepat dari 10 ^ 6 dan masih cukup untuk menunjukkan perbedaannya.) Lihat juga demo yang lebih kasar dan lebih visual dan sedikit kekonyolan ini menunjukkan itu bekerja pada input besar di mana semua string frekuensi tinggi .dieharder
tampaknya semua nol. Dengan asumsi ini bukan hanya kesalahan aneh di pihak saya, itu pasti akan menjelaskan mengapa itu tidak acak! Apakah Anda mendapatkan data yang terlihat bagus jika Anda menjalankannyawhile echo $(( RANDOM << 17 | RANDOM << 2 | RANDOM >> 13 )); do :; done | perl -ne 'print pack "I>"' > out
sebentar dan kemudian memeriksa isinyaout
dengan hex editor? (Atau melihatnya namun lain Anda seperti.) Saya mendapatkan semua nol, danRANDOM
tidak pelakunya: saya mendapatkan semua nol ketika saya mengganti$(( RANDOM << 17 | RANDOM << 2 | RANDOM >> 13 ))
dengan100
, juga.Katakanlah Anda punya file
notifications.txt
. Kita perlu menghitung jumlah garis, untuk menentukan rentang generator acak:Mari kita menulis ke variabel:
Sekarang untuk menghasilkan angka dari
0
ke$LINE
kita akan menggunakanRANDOM
variabel.Mari kita tulis ke variabel:
Sekarang kita hanya perlu mencetak nomor baris ini:
Tentang ACAK:
Pastikan file Anda memiliki kurang dari 32767 nomor baris. Lihat ini jika Anda memerlukan generator acak yang lebih besar yang berfungsi di luar kotak.
Contoh:
sumber
LINES=$(wc -l < file.txt); R_LINE=$((RANDOM % LINES)); sed -n "${R_LINE}p" file.txt
$RANDOM % n
dapat membelokkan distribusi acak Anda meskipun$RANDOM
itu sendiri ok% n
ke angka acak.Berikut skrip Python yang memilih garis acak dari file input atau stdin:
Algoritma ini adalah O (n) -waktu, O (1) -ruang. Ini berfungsi untuk file yang lebih besar dari 32767 baris. Itu tidak memuat file input ke dalam memori. Bunyinya setiap baris input persis sekali yaitu, Anda dapat menyalurkan konten besar (tapi terbatas) sembarangan ke dalamnya. Berikut penjelasan algoritma .
sumber
Saya terkesan dengan pekerjaan yang dilakukan Malte Skoruppa dan yang lainnya, tetapi di sini ada cara "bash murni" yang jauh lebih sederhana untuk melakukannya:
Seperti yang telah dicatat beberapa orang, $ ACAK tidak acak. Namun, batas ukuran file 32767 baris diatasi dengan merangkai $ ACAK bersama-sama sesuai kebutuhan.
sumber