Saya mencoba naif:
$ cat * | sort -u > /tmp/bla.txt
yang gagal dengan:
-bash: /bin/cat: Argument list too long
Jadi untuk menghindari solusi konyol seperti (membuat file sementara yang sangat besar):
$ find . -type f -exec cat {} >> /tmp/unsorted.txt \;
$ cat /tmp/unsorted.txt | sort -u > /tmp/bla.txt
Saya pikir saya bisa memproses file satu per satu menggunakan (ini akan mengurangi konsumsi memori, dan lebih dekat ke mekanisme streaming):
$ cat proc.sh
#!/bin/sh
old=/tmp/old.txt
tmp=/tmp/tmp.txt
cat $old "$1" | sort -u > $tmp
mv $tmp $old
Diikuti kemudian oleh:
$ touch /tmp/old.txt
$ find . -type f -exec /tmp/proc.sh {} \;
Apakah ada penggantian unix-style yang lebih sederhana untuk: cat * | sort -u
ketika jumlah file mencapai MAX_ARG
? Rasanya akward menulis skrip shell kecil untuk tugas umum seperti itu.
sort
melakukannya secara otomatis untuk input file multipel .. tapi kemudiansort -u *
akan gagalArgument list too long
juga saya kiraJawaban:
Dengan GNU
sort
, dan sebuah shell di manaprintf
built-in (semua yang seperti POSIX saat ini kecuali beberapa varianpdksh
):Sekarang, masalah dengan itu adalah karena dua komponen dari pipa itu dijalankan secara bersamaan dan independen, pada saat yang kiri memperluas
*
gumpalan, yang tepat mungkin telah membuatoutput
file yang dapat menyebabkan masalah (mungkin tidak dengan di-u
sini) seperti halnyaoutput
file input dan output, jadi Anda mungkin ingin agar outputnya pergi ke direktori lain (> ../output
misalnya), atau pastikan glob tidak cocok dengan file output.Cara lain untuk mengatasinya dalam contoh ini adalah dengan menuliskannya:
Dengan begitu, ini
sort
terbukaoutput
untuk menulis dan (dalam pengujian saya), itu tidak akan melakukannya sebelum menerima daftar lengkap file (begitu lama setelah gumpalan telah diperluas). Ini juga akan menghindari clobberingoutput
jika tidak ada file input yang dapat dibaca.Cara lain untuk menulisnya dengan
zsh
ataubash
Itu menggunakan proses substitusi (di mana
<(...)
digantikan oleh path file yang merujuk ke ujung pipa membacaprintf
untuk menulis). Fitur itu berasalksh
, tetapiksh
bersikeras membuat perluasan<(...)
argumen terpisah ke perintah sehingga Anda tidak dapat menggunakannya dengan--option=<(...)
sintaks. Akan bekerja dengan sintaks ini:Perhatikan bahwa Anda akan melihat perbedaan dari pendekatan yang mengumpankan output
cat
pada file dalam kasus di mana ada file yang tidak berakhir dengan karakter baris baru:Perhatikan juga bahwa
sort
mengurutkan menggunakan algoritme collation di locale (strcollate()
), dansort -u
melaporkan salah satu dari setiap set baris yang mengurutkan yang sama dengan algoritma itu, bukan garis unik pada level byte. Jika Anda hanya peduli tentang garis yang unik pada tingkat byte dan tidak terlalu peduli tentang urutannya, Anda mungkin ingin memperbaiki lokal ke C di mana penyortiran didasarkan pada nilai byte (memcmp()
; yang mungkin akan mempercepat segalanya secara signifikan):sumber
sort
untuk mengurangi konsumsi memorinya. Saya masih menemukanprintf '%s\0' *
sedikit rumit untuk diketik.find . -type f -maxdepth 1 -print0
bukanprintf '%s\0' *
, tapi saya tidak bisa mengklaim itu lebih mudah untuk diketik. Dan yang terakhir lebih mudah untuk didefinisikan sebagai alias, tentu saja!echo
memang memiliki-n
, saya lebih suka sesuatu sepertiprintf -0 %s
ini tampaknya tingkat yang sedikit lebih rendah daripada'%s\0'
-maxdepth
dan-print0
merupakan ekstensi GNU (meskipun banyak didukung hari ini). Dengan yang lainfind
(walaupun jika Anda memiliki jenis GNU, Anda kemungkinan juga akan menemukan GNU), Anda dapat melakukannyaLC_ALL=C find . ! -name . -prune -type f ! -name '.*' -exec printf '%s\0' {} +
(LC_ALL=C
masih mengecualikan file tersembunyi yang berisi karakter yang tidak valid, bahkan dengan GNUfind
), tetapi itu sedikit berlebihan ketika Anda secara umum memilikiprintf
builtin.print0
fungsi sebagaiprint0() { [ "$#" -eq 0 ] || printf '%s\0' "$@";}
dan kemudianprint0 * | sort...
Perbaikan sederhana, bekerja setidaknya di Bash, karena
printf
sudah dibangun, dan batas argumen baris perintah tidak berlaku untuk itu:(
echo * | xargs
juga akan berfungsi, kecuali untuk penanganan nama file dengan spasi putih, dll.)sumber
cat
proses terpisah untuk setiap file.find -exec {} +
mengumpulkan banyak file per satu eksekusi. Denganfind -exec \;
itu akan menjadi satu kucing per file.Ini akan menggabungkan semua file biasa yang tidak tersembunyi di direktori saat ini dan mengurutkan konten gabungannya (sambil menghapus garis yang digandakan) ke dalam file
/path/to/sorted.txt
.sumber
|
operasi rantai akan benar membatasi penggunaan memori?sort
akan melakukan semacam out-of-core jika persyaratan memori memerlukannya. Sisi kiri pipa akan mengkonsumsi sangat sedikit memori dibandingkan.Efisiensi adalah istilah relatif sehingga Anda benar-benar harus menentukan faktor mana yang ingin Anda kurangi; cpu, memori, disk, waktu dll. Demi argumen, saya akan berasumsi bahwa Anda ingin meminimalkan penggunaan memori dan bersedia menghabiskan lebih banyak siklus cpu untuk mencapainya. Solusi seperti yang diberikan oleh Stéphane Chazelas bekerja dengan baik
tetapi mereka menganggap bahwa file teks individu memiliki tingkat keunikan yang tinggi untuk memulai. Jika tidak, yaitu setelah
sample.srt lebih dari 10% lebih kecil dari sample.txt maka Anda akan menghemat memori yang signifikan dengan menghapus duplikat di dalam file sebelum Anda bergabung. Anda juga akan menghemat lebih banyak memori dengan tidak merantai perintah yang berarti hasil dari proses yang berbeda tidak perlu berada di memori pada saat yang sama.
sumber
sort
karenasort
resor menggunakan file sementara ketika penggunaan memori melampaui ambang batas (biasanya relatif kecil).base64 /dev/urandom | sort -u
akan mengisi disk Anda tetapi tidak menggunakan banyak memori.sort
implementasi termasuk yang asli di Unix v3 pada tahun 1972, tetapi tampaknya bukan daribusybox sort
. Mungkin karena itu dimaksudkan untuk berjalan pada sistem kecil yang tidak memiliki penyimpanan permanen.yes | sort -u
(semua data duplikat) tidak harus menggunakan lebih dari beberapa byte memori, apalagi disk. Tetapisort
setidaknya dengan GNU dan Solaris , kami melihatnya menulis banyak file besar 2 byte/tmp
(y\n
untuk setiap beberapa megabita input) sehingga akhirnya akan mengisi disk.Seperti @ilkkachu, tetapi kucing (1) tidak perlu:
Juga, Jika datanya terlalu lama, Anda mungkin ingin menggunakan opsi sortir (1) --parallel = N
Ketika N adalah jumlah CPU yang dimiliki komputer Anda
sumber