Saya memiliki beberapa ratus PDF di bawah direktori di UNIX. Nama-nama PDF sangat panjang (sekitar 60 karakter).
Ketika saya mencoba menghapus semua PDF bersama-sama menggunakan perintah berikut:
rm -f *.pdf
Saya mendapatkan kesalahan berikut:
/bin/rm: cannot execute [Argument list too long]
Apa solusi untuk kesalahan ini? Apakah kesalahan ini terjadi untuk mv
dan juga cp
perintah? Jika ya, bagaimana cara menyelesaikan perintah ini?
Jawaban:
Alasan ini terjadi adalah karena bash sebenarnya memperluas tanda bintang ke setiap file yang cocok, menghasilkan baris perintah yang sangat panjang.
Coba ini:
Peringatan: ini adalah pencarian rekursif dan akan menemukan (dan menghapus) file di subdirektori juga. Tack on
-f
ke perintah rm hanya jika Anda yakin tidak ingin konfirmasi.Anda dapat melakukan hal berikut untuk membuat perintah tidak rekursif:
Pilihan lain adalah menggunakan
-delete
flag find :sumber
xargs
secara khusus membagi daftar dan mengeluarkan beberapa perintah jika perlu.-maxdepth 1
perlu argumen pertama setelah jalan.-delete
flag untuk menghapus file yang ditemukannya, dan bahkan jika tidak, itu masih dianggap praktik yang lebih baik untuk digunakan-exec
untuk mengeksekusi rm, daripada memanggil xargs (yang sekarang 3 proses dan pipa bukannya proses tunggal dengan-delete
atau 2 proses dengan-exec
).dangerous (broken, exploitable, etc.)
, cukup konyol. Tidak diragukan lagi Anda harus berhati-hati saat menggunakanxargs
, tetapi itu tidak cukupeval/evil
.-exec
memanggilrm
, jumlah proses akan menjadi 1 + jumlah file, meskipun jumlah proses bersamaan dari ini mungkin 2 (mungkin menemukan akan menjalankan proses rm secara bersamaan). Jumlah proses menggunakanxargs
akan dikurangi secara dramatis menjadi 2 + n, di mana n adalah beberapa proses nomor kurang dari jumlah file (katakanlah jumlah file / 10, meskipun kemungkinan lebih tergantung pada panjang jalur). Dengan asumsi find melakukan penghapusan secara langsung, menggunakan-delete
harus menjadi satu-satunya proses yang akan dipanggil.tl; dr
Ini adalah batasan kernel pada ukuran argumen baris perintah. Gunakan
for
loop sebagai gantinya.Asal masalah
Ini adalah masalah sistem, terkait dengan
execve
danARG_MAX
konstan. Ada banyak dokumentasi tentang itu (lihat man execve , wiki debian ).Pada dasarnya, ekspansi menghasilkan perintah (dengan parameternya) yang melebihi
ARG_MAX
batas. Pada kernel2.6.23
, batasnya ditetapkan pada128 kB
. Konstanta ini telah ditingkatkan dan Anda bisa mendapatkan nilainya dengan mengeksekusi:Solusi: Menggunakan
for
LoopGunakan
for
loop seperti yang disarankan pada BashFAQ / 095 dan tidak ada batasan kecuali untuk ruang RAM / memori:Dry run untuk memastikan itu akan menghapus apa yang Anda harapkan:
Dan jalankan:
Ini juga merupakan pendekatan portabel karena glob memiliki perilaku yang kuat dan konsisten di antara shell ( bagian dari POSIX spec ).
Catatan: Sebagaimana dicatat oleh beberapa komentar, ini memang lebih lambat tetapi lebih dapat dipelihara karena dapat mengadaptasi skenario yang lebih kompleks, misalnya di mana seseorang ingin melakukan lebih dari satu tindakan.
Solusi: Menggunakan
find
Jika Anda bersikeras, Anda dapat menggunakan
find
tetapi benar - benar tidak menggunakan xargs karena "berbahaya (rusak, dapat dieksploitasi, dll.) Saat membaca input yang tidak dibatasi NUL" :Menggunakan
-maxdepth 1 ... -delete
alih-alih-exec rm {} +
memungkinkanfind
untuk hanya menjalankan pemanggilan sistem yang diperlukan sendiri tanpa menggunakan proses eksternal, karenanya lebih cepat (terima kasih atas komentar @chepner ).Referensi
sumber
for
loop. Saya pernah menggunakanfind
sebelumnya, tapi saya selalu mencari cara melakukannya karena saya lupa pilihan, dll. Sepanjang waktu.for
tampaknya lebih mudah untuk mengingat IMHOfor f in *; do rm "$f"; done
pesonafind -exec
solusi tampaknya JAUH lebih cepat darifor
lingkaran.4.15.0-1019-gcp
tepatnya) dan batasnya masih pada 2097152. Cukup menarik, mencari ARG_MAX di repo git linux memberikan hasil yang menunjukkan ARG_MAX berada di 131702.find
memiliki-delete
tindakan:sumber
xargs
, sesuai jawaban Dennis, berfungsi sebagaimana dimaksud.-exec
adalah untuk menghapus banyak file.-exec rm {} +
akan melakukan hal yang sama, tetapi masih membutuhkan memulai setidaknya satu proses eksternal.-delete
memungkinkanfind
untuk hanya menjalankan pemanggilan sistem yang diperlukan itu sendiri tanpa menggunakan pembungkus eksternal.Jawaban lain adalah memaksa
xargs
untuk memproses perintah dalam batch. Misalnya kedelete
file100
sekaligus,cd
masuk ke direktori dan jalankan ini:echo *.pdf | xargs -n 100 rm
sumber
echo
shell dibangun. Jika Anda akhirnya menggunakan perintahecho
, Anda masih akan berlari ke batas argumen program.Atau Anda dapat mencoba:
sumber
find . -maxdepth 1 -name '*.pdf' -exec rm -f {} \;
Jika Anda mencoba menghapus sejumlah besar file sekaligus (saya menghapus direktori dengan 485.000+ hari ini), Anda mungkin akan mengalami kesalahan ini:
Masalahnya adalah ketika Anda mengetik sesuatu seperti
rm -rf *
,*
diganti dengan daftar setiap file yang cocok, seperti "rm -rf file1 file2 file3 file4" dan seterusnya. Ada buffer memori yang relatif kecil yang dialokasikan untuk menyimpan daftar argumen ini dan jika diisi, shell tidak akan menjalankan program.Untuk mengatasi masalah ini, banyak orang akan menggunakan perintah find untuk menemukan setiap file dan meneruskannya satu per satu ke perintah "rm" seperti ini:
Masalah saya adalah saya harus menghapus 500.000 file dan itu terlalu lama.
Saya menemukan cara yang jauh lebih cepat untuk menghapus file - perintah "find" memiliki bendera "-delete" yang ada di dalamnya! Inilah yang akhirnya saya gunakan:
Dengan menggunakan metode ini, saya menghapus file dengan kecepatan sekitar 2000 file / detik - jauh lebih cepat!
Anda juga dapat menampilkan nama file saat Anda menghapusnya:
... atau bahkan menunjukkan berapa banyak file yang akan dihapus, lalu berapa lama waktu yang dibutuhkan untuk menghapusnya:
sumber
sudo find . -type f -delete
untuk menghapus sekitar 485 ribu file dan itu berhasil untuk saya. Butuh waktu sekitar 20 detik.Anda dapat mencoba ini:
EDIT: Komentar ThiefMaster menyarankan saya untuk tidak mengungkapkan praktik berbahaya seperti itu kepada jedis shell muda, jadi saya akan menambahkan versi yang lebih "lebih aman" (demi menjaga hal-hal ketika seseorang memiliki file "-rf. ... pdf")
Setelah menjalankan hal di atas, cukup buka file /tmp/dummy.sh di fav Anda. edit dan periksa setiap baris untuk nama file berbahaya, beri komentar jika ditemukan.
Kemudian salin skrip dummy.sh di direktori kerja Anda dan jalankan.
Semua ini untuk alasan keamanan.
sumber
-rf .. .pdf
-rf
lebih diutamakan-i
, sehingga versi 2 Anda tidak lebih baik (tanpa inspeksi manual). Dan pada dasarnya tidak berguna untuk penghapusan massal, karena meminta setiap file.Anda bisa menggunakan array bash:
Dengan cara ini akan dihapus dalam batch 1000 file per langkah.
sumber
Anda dapat menggunakan pujian ini
sumber
The rm perintah memiliki keterbatasan file yang dapat Anda menghapus simultan.
Satu kemungkinan Anda dapat menghapusnya menggunakan beberapa kali perintah rm berdasarkan pola file Anda, seperti:
Anda juga dapat menghapusnya melalui perintah find :
sumber
rm
tidak memiliki batasan jumlah file yang akan diproses (selain ituargc
tidak boleh lebih besar dariINT_MAX
). Ini keterbatasan kernel pada ukuran maksimum dari seluruh argumen array (itu sebabnya panjang nama file signifikan).Jika mereka adalah nama file dengan spasi atau karakter khusus, gunakan:
Kalimat ini mencari semua file di direktori saat ini (-maxdepth 1) dengan ekstensi pdf (-name '* .pdf'), dan kemudian hapus masing-masing (-exec rm "{}").
Ekspresi {} ganti nama file, dan, {{} "tetapkan nama file sebagai string, termasuk spasi atau karakter khusus.
sumber
-exec
adalah bahwa Anda tidak meminta shell. Kutipan di sini sama sekali tidak berguna. (Mereka mencegah ekspansi wildcard dan pemisahan token pada string di shell tempat Anda mengetik perintah ini, tetapi string{}
tidak mengandung spasi atau karakter wildcard shell.)saya menghadapi masalah yang sama saat menyalin direktori sumber formulir ke tujuan
direktori sumber memiliki file ~ 3 lakc
saya menggunakan cp dengan opsi -r dan itu berhasil untuk saya
cp -r abc / def /
itu akan menyalin semua file dari abc ke def tanpa memberi peringatan daftar Argument terlalu lama
sumber
Coba ini juga Jika Anda ingin menghapus di atas 30/90 hari (+) atau yang lain di bawah 30/90 (-) hari file / folder maka Anda dapat menggunakan perintah ex di bawah ini
Mis: Selama 90 hari tidak termasuk di atas setelah 90 hari menghapus file / folder, itu berarti 91,92 .... 100 hari
Mis: Hanya file 30 hari terbaru yang ingin Anda hapus kemudian gunakan perintah di bawah ini (-)
Jika Anda ingin giz file selama lebih dari 2 hari file
Jika Anda ingin melihat file / folder hanya dari satu bulan terakhir. Ex:
Di atas 30 hari lagi hanya daftar file / folder Mis:
sumber
Saya terkejut tidak ada
ulimit
jawaban di sini. Setiap kali saya memiliki masalah ini, saya berakhir di sini atau di sini . Saya mengerti solusi ini memiliki keterbatasan tetapiulimit -s 65536
sepertinya sering melakukan trik untuk saya.sumber
Saya memiliki masalah yang sama dengan folder yang penuh dengan gambar sementara yang tumbuh hari demi hari dan perintah ini membantu saya menghapus folder
Perbedaannya dengan perintah lain adalah parameter mtime yang hanya akan mengambil file yang lebih lama dari X hari (dalam contoh 50 hari)
Menggunakan itu berkali-kali, berkurang pada setiap eksekusi dalam rentang hari, saya dapat menghapus semua file yang tidak perlu
sumber
Saya hanya tahu cara mengatasinya. Idenya adalah untuk mengekspor daftar file pdf yang Anda miliki ke file. Kemudian bagi file itu menjadi beberapa bagian. Kemudian hapus file pdf yang tercantum di setiap bagian.
wc -l adalah untuk menghitung berapa banyak baris yang ada di list.txt. Ketika Anda memiliki gagasan tentang berapa lama, Anda dapat memutuskan untuk membaginya menjadi dua, empat atau seterusnya. Menggunakan perintah split -l Misalnya, pisahkan masing-masing dalam 600 baris.
ini akan membuat beberapa file bernama xaa, xab, xac dan sebagainya tergantung pada bagaimana Anda membaginya. Sekarang untuk "mengimpor" setiap daftar dalam file tersebut ke dalam perintah rm, gunakan ini:
Maaf untuk bahasa Inggris saya yang buruk.
sumber
pdf_format_sucks.docx
ini, ini akan dihapus juga ... ;-) Anda harus menggunakan ekspresi reguler yang tepat dan akurat ketika menerima file pdf.still_pdf_format_sucks.docx
akan dihapus. Titik.
dalam".pdf"
ekspresi reguler cocok dengan karakter apa pun. Saya akan menyarankan"[.]pdf$"
bukan.pdf
.Saya mengalami masalah ini beberapa kali. Banyak solusi akan menjalankan
rm
perintah untuk setiap file yang perlu dihapus. Ini sangat tidak efisien:Saya akhirnya menulis skrip python untuk menghapus file berdasarkan 4 karakter pertama dalam nama file:
Ini bekerja sangat baik untuk saya. Saya dapat menghapus lebih dari 2 juta file temp dalam folder dalam waktu sekitar 15 menit. Saya berkomentar tar keluar dari sedikit kode sehingga siapa pun dengan sedikit atau tanpa pengetahuan python dapat memanipulasi kode ini.
sumber
Dan satu lagi:
printf
adalah shell builtin, dan sejauh yang saya tahu selalu seperti itu. Sekarang mengingat bahwaprintf
itu bukan perintah shell (tapi builtin), itu tidak tunduk pada "argument list too long ...
" kesalahan fatal.Jadi kita dapat menggunakannya dengan aman dengan pola-pola shell globbing seperti
*.[Pp][Dd][Ff]
, kemudian kita mem-pipe outputnya untuk menghapus (rm
) perintah, melaluixargs
, yang memastikan itu cukup cocok dengan nama file di baris perintah agar tidak gagalrm
perintah, yang merupakan shell perintah.The
\0
dalamprintf
Melayani sebagai pemisah null untuk nama file Wich kemudian diproses olehxargs
perintah, menggunakannya (-0
) sebagai pemisah, sehinggarm
tidak gagal ketika ada spasi putih atau karakter khusus lainnya dalam nama file.sumber
printf
shell tidak dibangun, itu akan dikenakan batasan yang sama.Anda dapat membuat folder temp, memindahkan semua file dan sub-folder yang ingin Anda simpan ke folder temp lalu menghapus folder lama dan mengganti nama folder temp ke folder lama coba contoh ini sampai Anda yakin untuk melakukannya langsung:
yang
rm -r big_folder
akan menghapus semua file dalambig_folder
tidak peduli berapa banyak. Anda hanya harus sangat berhati-hati terlebih dahulu untuk memiliki semua file / folder yang ingin Anda simpan, dalam hal inifile1.pdf
sumber
Untuk menghapus semua
*.pdf
dalam direktori/path/to/dir_with_pdf_files/
Untuk menghapus file tertentu melalui
rsync
menggunakan wildcard mungkin merupakan solusi tercepat jika Anda memiliki jutaan file. Dan itu akan mengatasi kesalahan yang Anda dapatkan.(Langkah Opsional): KERING KERING. Untuk memeriksa apa yang akan dihapus tanpa menghapus. `
. . .
Klik tips dan trik rsync untuk hacks rsync lainnya
sumber
Saya menemukan bahwa untuk daftar file yang sangat besar (> 1e6), jawaban ini terlalu lambat. Berikut adalah solusi menggunakan pemrosesan paralel dalam python. Saya tahu, saya tahu, ini bukan linux ... tapi tidak ada yang bekerja di sini.
(Ini menghemat waktu saya)
sumber
Saya telah menghadapi masalah yang sama ketika ada jutaan file log tidak berguna yang dibuat oleh aplikasi yang mengisi semua inode. Saya terpaksa "mencari", mendapatkan semua file "terletak" d ke file teks dan kemudian menghapusnya satu per satu. Butuh waktu tetapi melakukan pekerjaan!
sumber
locate
kembali ketika Anda masih memiliki ruang pada disk Anda.Versi yang sedikit lebih aman daripada menggunakan xargs, juga tidak rekursif:
ls -p | grep -v '/$' | grep '\.pdf$' | while read file; do rm "$file"; done
Memfilter direktori kami di sini sedikit tidak perlu karena 'rm' tidak akan menghapusnya, dan itu dapat dihapus untuk kesederhanaan, tetapi mengapa menjalankan sesuatu yang pasti akan mengembalikan kesalahan?
sumber
ls
adalah antipattern umum yang harus dihindari, dan menambahkan sejumlah bug tambahan di sini. Hanyagrep | grep
saja tidak terlalu elegan.find
bagus, dan didokumentasikan dengan baik di sini dan di tempat lain. Lihat misalnya mywiki.wooledge.org untuk informasi lebih lanjut tentang ini dan topik terkait.Menggunakan GNU parallel (
sudo apt install parallel
) sangat mudahItu menjalankan perintah multithreaded di mana '{}' adalah argumen yang dilewati
Misalnya
ls /tmp/myfiles* | parallel 'rm {}'
sumber
ls
langsung ke perintah lain adalah antipattern yang berbahaya - itu, dan fakta bahwa ekspansi wildcard akan menyebabkan kegagalan yang sama ketika mengeksekusils
seperti yang dialami seperti yang dialami padarm
perintah asli .parallel
membuat beberapa orang yang lebih suka menghindari kerumitan tidak nyaman - jika Anda melihat di bawah tenda, itu cukup buram. Lihat utas milis di lists.gnu.org/archive/html/bug-parallel/2015-05/msg00005.html antara Stephane (salah satu dari Unix & Linux StackExchange greybeards) dan Ole Tange (penulis paralel).xargs -P
juga lumpuh, tetapi melakukannya dengan cara yang lebih sederhana dan bodoh dengan bagian bergerak yang lebih sedikit, membuat perilakunya jauh lebih mudah untuk diprediksi dan dipikirkan.Untuk menghapus 100 file pertama:
rm -rf 'ls | kepala -100 '
sumber
Opsi di bawah ini tampaknya sederhana untuk masalah ini. Saya mendapat info ini dari utas lain tetapi itu membantu saya.
Jalankan saja satu perintah di atas dan itu akan melakukan tugas.
sumber