Misalkan Anda memiliki file yang berisi alamat IP, satu alamat di setiap baris:
10.0.10.1
10.0.10.1
10.0.10.3
10.0.10.2
10.0.10.1
Anda memerlukan skrip shell yang menghitung untuk setiap alamat IP berapa kali muncul dalam file. Untuk input sebelumnya, Anda memerlukan output berikut:
10.0.10.1 3
10.0.10.2 1
10.0.10.3 1
Salah satu cara untuk melakukan ini adalah:
cat ip_addresses |uniq |while read ip
do
echo -n $ip" "
grep -c $ip ip_addresses
done
Namun itu jauh dari efisien.
Bagaimana Anda memecahkan masalah ini secara lebih efisien menggunakan bash?
(Satu hal untuk ditambahkan: Saya tahu ini bisa diselesaikan dari perl atau awk, saya tertarik pada solusi yang lebih baik dalam bash, bukan dalam bahasa itu.)
INFORMASI TAMBAHAN:
Misalkan file sumber 5GB dan mesin yang menjalankan algoritma 4GB. Jadi sort bukanlah solusi yang efisien, juga tidak membaca file lebih dari sekali.
Saya menyukai solusi seperti hashtable - siapa pun dapat memberikan peningkatan pada solusi itu?
INFO TAMBAHAN # 2:
Beberapa orang bertanya mengapa saya repot-repot melakukannya di bash ketika itu jauh lebih mudah di misalnya perl. Alasannya adalah bahwa pada mesin saya harus melakukan perl ini tidak tersedia untuk saya. Itu adalah mesin linux yang dibuat khusus tanpa sebagian besar alat yang biasa saya gunakan. Dan saya pikir itu masalah yang menarik.
Jadi tolong, jangan salahkan pertanyaannya, abaikan saja jika Anda tidak menyukainya. :-)
Jawaban:
Ini akan mencetak hitungan pertama, tetapi selain itu harus persis apa yang Anda inginkan.
sumber
sort ip_addresses | uniq -c | sort -nr
sort ip_addresses | uniq -c | sort -nr | awk '{ print $2, $1 }'
untuk mendapatkan alamat ip di kolom pertama dan hitung di kolom kedua.sort -nr -k1,1
Metode cepat dan kotor adalah sebagai berikut:
cat ip_addresses | sort -n | uniq -c
Jika Anda perlu menggunakan nilai-nilai dalam bash Anda dapat menetapkan seluruh perintah ke variabel bash dan kemudian mengulangi hasilnya.
PS
Jika perintah sortir dihilangkan, Anda tidak akan mendapatkan hasil yang benar karena uniq hanya melihat garis identik yang berurutan.
sumber
untuk menjumlahkan beberapa bidang, berdasarkan sekelompok bidang yang ada, gunakan contoh di bawah ini: (ganti $ 1, $ 2, $ 3, $ 4 sesuai dengan kebutuhan Anda)
sumber
sort
danuniq
paling mudah untuk melakukan penghitungan, tetapi tidak membantu ketika Anda perlu menghitung / menjumlahkan nilai bidang. Sintaks array awk sangat kuat dan kunci untuk pengelompokan di sini. Terima kasih!print
fungsi tampaknya downscale 64 bit bilangan bulat 32 bit, sehingga nilai-nilai int melebihi 2 ^ 31 Anda mungkin ingin menggunakanprintf
dengan%.0f
format yang bukanprint
adaarr[$1,$2]+=$3+$4
dengan misalnyaarr[$1,$2]=(arr[$1,$2] $3 "," $4). I needed this to provide a grouped-by-package list of files (two columns only) and used:
arr [$ 1] = (arr [$ 1] $ 2) `dengan sukses.Solusi kanonik adalah yang disebutkan oleh responden lain:
Ini lebih pendek dan lebih ringkas daripada apa yang dapat ditulis dalam Perl atau awk.
Anda menulis bahwa Anda tidak ingin menggunakan pengurutan, karena ukuran data lebih besar dari ukuran memori utama mesin. Jangan meremehkan kualitas implementasi dari perintah sort Unix. Sortir digunakan untuk menangani volume data yang sangat besar (pikirkan data penagihan AT&T asli) pada mesin dengan 128k (yaitu 131.072 byte) memori (PDP-11). Ketika sortir menemukan lebih banyak data daripada batas yang telah ditentukan (sering disetel mendekati ukuran memori utama mesin) itu mengurutkan data yang telah dibaca dalam memori utama dan menulisnya ke dalam file sementara. Kemudian mengulangi tindakan dengan potongan data berikutnya. Akhirnya, ia melakukan semacam penggabungan pada file-file perantara. Ini memungkinkan sortir bekerja pada data beberapa kali lebih besar dari memori utama mesin.
sumber
perintah ini akan memberi Anda output yang diinginkan
sumber
Tampaknya Anda harus menggunakan sejumlah besar kode untuk mensimulasikan hash dalam bash untuk mendapatkan perilaku linier atau tetap berpegang pada
kuadratikversi superlinear .Di antara versi tersebut, solusi saua adalah yang terbaik (dan paling sederhana):
Saya menemukan http://unix.derkeiler.com/Newsgroups/comp.unix.shell/2005-11/0118.html . Tapi itu jelek sekali ...
sumber
Solusi (dikelompokkan berdasarkan like mysql)
Hasil
sumber
Anda mungkin dapat menggunakan sistem file itu sendiri sebagai tabel hash. Kode semu sebagai berikut:
Pada akhirnya, yang perlu Anda lakukan adalah menelusuri semua file dan mencetak nama dan nomor file di dalamnya. Sebagai alternatif, alih-alih menyimpan hitungan, Anda dapat menambahkan spasi atau baris baru setiap kali ke file, dan pada akhirnya hanya melihat ukuran file dalam byte.
sumber
Saya merasa array asosiatif awk juga berguna dalam kasus ini
Grup lewat pos di sini
sumber
Sebagian besar solusi lain menghitung duplikat. Jika Anda benar-benar perlu mengelompokkan pasangan nilai kunci, coba ini:
Berikut ini contoh data saya:
Ini akan mencetak pasangan nilai kunci yang dikelompokkan oleh checksum MD5.
sumber
Murni pesta (tanpa garpu!)
Ada caranya, menggunakan a pestafungsi . Cara ini sangat cepat karena tidak ada garpu! ...
... Sementara sekelompok alamat ip tetap kecil !
Catatan: Alamat IP dikonversi menjadi nilai integer 32 bit yang tidak ditandai, digunakan sebagai indeks untuk array . Ini menggunakan array bash sederhana , bukan array asosiatif (yang lebih mahal)!
Di host saya, melakukannya jauh lebih cepat daripada menggunakan garpu, hingga kira-kira 1'000 alamat, tetapi ambil kira-kira 1 seluruh detik ketika saya akan mencoba mengurutkan'n menghitung 10'000 alamat.
sumber
Saya akan melakukannya seperti ini:
tetapi uniq mungkin bekerja untuk Anda.
sumber
Saya mengerti Anda sedang mencari sesuatu di Bash, tetapi kalau-kalau ada orang lain yang mencari sesuatu dengan Python, Anda mungkin ingin mempertimbangkan ini:
Karena nilai dalam himpunan unik secara default dan Python cukup bagus dalam hal ini, Anda mungkin memenangkan sesuatu di sini. Saya belum menguji kodenya, jadi mungkin disadap, tetapi ini mungkin akan membawa Anda ke sana. Dan jika Anda ingin menghitung kejadian, menggunakan dict bukan set mudah untuk diimplementasikan.
Sunting: Saya seorang pembaca yang buruk, jadi saya menjawab salah. Berikut cuplikan dengan dikt yang akan menghitung kejadian.
Kamus mydict sekarang menyimpan daftar kunci unik IP sebagai dan berapa kali mereka muncul sebagai nilainya.
sumber
itertools.groupby()
yang dikombinasikan dengansorted()
melakukan persis apa yang diminta OP.Sortir dapat dihilangkan jika pesanan tidak signifikan
atau
jika daftar sumber adalah variabel
sumber