Saya memiliki folder dengan lebih dari satu juta file yang perlu disortir, tetapi saya tidak dapat melakukan apa-apa karena mv
menampilkan pesan ini sepanjang waktu
-bash: /bin/mv: Argument list too long
Saya menggunakan perintah ini untuk memindahkan file ekstensi-kurang:
mv -- !(*.jpg|*.png|*.bmp) targetdir/
Jawaban:
xargs
adalah alat untuk pekerjaan itu. Itu, ataufind
dengan-exec … {} +
. Alat-alat ini menjalankan perintah beberapa kali, dengan sebanyak mungkin argumen yang dapat dilewati dalam sekali jalan.Kedua metode lebih mudah dilakukan ketika daftar argumen variabel di akhir, yang tidak terjadi di sini: argumen terakhir
mv
adalah tujuannya. Dengan utilitas GNU (yaitu pada Linux yang tidak tertanam atau Cygwin),-t
opsi untukmv
berguna, untuk melewati tujuan terlebih dahulu.Jika nama file tidak memiliki spasi putih atau apapun
\"'
, maka Anda dapat memberikan nama file sebagai inputxargs
(echo
perintahnya adalah bash builtin, sehingga tidak tunduk pada batas panjang baris perintah):Anda dapat menggunakan
-0
opsi untukxargs
menggunakan input yang dibatasi-nol alih-alih format kuotasi default.Atau, Anda dapat membuat daftar nama file dengan
find
. Untuk menghindari pengulangan ke subdirektori, gunakan-type d -prune
. Karena tidak ada tindakan yang ditentukan untuk file gambar yang terdaftar, hanya file lain yang dipindahkan.(Ini termasuk file dot, tidak seperti metode wildcard shell.)
Jika Anda tidak memiliki utilitas GNU, Anda dapat menggunakan shell perantara untuk mendapatkan argumen dalam urutan yang benar. Metode ini berfungsi pada semua sistem POSIX.
Di zsh, Anda dapat memuat
mv
builtin :atau jika Anda lebih suka membiarkan
mv
dan nama lain terus mengacu pada perintah eksternal:atau dengan gumpalan ksh-style:
Atau, gunakan GNU
mv
danzargs
:sumber
shopt -s extglob
mengaktifkannya. Saya melewatkan langkah dalamfind
perintah, saya sudah memperbaikinya.find
Perintah - perintah yang saya posting (sekarang) berfungsi. Anda harus meninggalkan bagian ketika menyalin-menempel.!
,? Ini lebih eksplisit dan lebih mudah dipahami daripada trailing aneh-o
. Misalnya,! -name '*.jpg' -a ! -name '*.png' -a ! -name '*.bmp'
Jika bekerja dengan kernel Linux sudah cukup, Anda cukup melakukannya
itu akan berfungsi karena kernel Linux menyertakan tambalan sekitar 10 tahun yang lalu yang mengubah batas argumen berdasarkan ukuran tumpukan: https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/ komit /? id = b6a2fea39318e43fee84fa7b0b90d68bed92d2ba
Perbarui: Jika Anda merasa berani, Anda bisa mengatakannya
dan Anda akan baik-baik saja dengan ekspansi shell apa pun selama Anda memiliki cukup RAM.
sumber
ulimit -s unlimited
dan itu akan berfungsi untuk file yang praktis tidak terbatas.ulimit -s unlimited
batas baris perintah aktual adalah 2 ^ 31 atau 2 GB. (MAX_ARG_STRLEN
dalam sumber kernel.)Batas kelalaian argumen sistem operasi tidak berlaku untuk ekspansi yang terjadi di dalam shell interpreter. Jadi selain menggunakan
xargs
ataufind
, kita bisa menggunakan shell loop untuk memecah pemrosesan menjadimv
perintah - perintah individual :Ini hanya menggunakan fitur dan utilitas POSIX Shell Command Language. Satu garis ini lebih jelas dengan lekukan, dengan titik koma yang tidak perlu dihapus:
sumber
mv
proses, alih-alih hanya beberapa yang dibutuhkan menggunakanfind
solusi POSIX @Gilles yang diposting. Dengan kata lain, cara ini menghasilkan banyak churn CPU yang tidak perlu.case
pernyataan hasil*
ekspansi untuk memfilter beberapa ekstensi setara dengan!(*.jpg|*.png|*.bmp)
ekspresi asli . Thefind
Jawabannya sebenarnya tidak setara; turun ke subdirektori (saya tidak melihat-maxdepth
predikat).-name . -o -type d -prune -o
melindungi dari turun ke sub-direktori.-maxdepth
tampaknya tidak sesuai dengan POSIX, meskipun itu tidak disebutkan difind
halaman manual saya .Untuk solusi yang lebih agresif daripada yang ditawarkan sebelumnya, tarik sumber kernel Anda dan edit
include/linux/binfmts.h
Tingkatkan ukuran
MAX_ARG_PAGES
menjadi sesuatu yang lebih besar dari 32. Ini meningkatkan jumlah memori yang akan diizinkan oleh kernel untuk argumen program, sehingga memungkinkan Anda menentukanmv
ataurm
perintah Anda untuk jutaan file atau apa pun yang Anda lakukan. Kompilasi ulang, instal, reboot.WASPADALAH! Jika Anda mengatur ini terlalu besar untuk memori sistem Anda, dan kemudian jalankan perintah dengan banyak argumen BURUK HAL AKAN TERJADI! Berhati-hatilah dalam melakukan hal ini pada sistem multi-pengguna, ini membuat lebih mudah bagi pengguna jahat untuk menggunakan semua memori Anda!
Jika Anda tidak tahu cara mengkompilasi ulang dan menginstal ulang kernel Anda secara manual, mungkin yang terbaik adalah Anda berpura-pura jawaban ini tidak ada untuk saat ini.
sumber
Solusi yang lebih sederhana menggunakan
"$origin"/!(*.jpg|*.png|*.bmp)
alih-alih blok tangkap:Terima kasih kepada @Score_Under
Untuk skrip multi-baris Anda dapat melakukan hal berikut (perhatikan
;
sebelumdone
dijatuhkan):Untuk melakukan solusi yang lebih umum yang memindahkan semua file, Anda bisa melakukan satu-baris:
Yang terlihat seperti ini jika Anda melakukan lekukan:
Ini mengambil setiap file dalam asal dan memindahkannya satu per satu ke tujuan. Kutipan di sekitar
$file
diperlukan jika ada spasi atau karakter khusus lainnya dalam nama file.Berikut adalah contoh metode ini yang bekerja dengan sempurna
sumber
!(*.jpg|*.png|*.bmp)
. Anda bisa menambahkan itu untuk for-loop Anda dengan globbing"$origin"/!(*.jpg|*.png|*.bmp)
yang akan menghindari kebutuhan untuk saklar yang digunakan dalam jawaban Kaz dan menjaga tubuh sederhana for-loop.Terkadang lebih mudah untuk hanya menulis skrip kecil, misalnya dengan Python:
sumber
Anda dapat mengatasi batasan itu saat masih menggunakan
mv
jika Anda tidak keberatan menjalankannya beberapa kali.Anda dapat memindahkan bagian sekaligus. Katakanlah misalnya Anda memiliki daftar panjang nama file alfanumerik.
Itu bekerja. Kemudian pukullah satu potongan besar lagi. Setelah beberapa bergerak, Anda bisa kembali menggunakan
mv ./subdir/* ./
sumber
Ini dua sen saya, tambahkan ini
.bash_profile
Pemakaian
sumber