Saya hanya mengajukan pertanyaan terkait bagaimana saya bisa menghitung file ekstensi tertentu. Sekarang saya ingin cp
file-file ini ke yang baru dir
.
Aku sedang mencoba,
cp *.prj ../prjshp/
dan
cp * | grep '\.prj$' ../prjshp/
tetapi mereka memberikan kesalahan yang sama,
bash: / bin / cp: Daftar argumen terlalu panjang
Bagaimana cara menyalinnya?
command-line
files
Sam007
sumber
sumber
Jawaban:
cp *.prj ../prjshp/
adalah perintah yang tepat, tetapi Anda telah menemukan kasus yang jarang terjadi di mana ia mengalami batasan ukuran. Perintah kedua yang Anda coba tidak masuk akal.Salah satu metode adalah menjalankan
cp
file dalam potongan. Thefind
Perintah tahu bagaimana melakukan ini:find
melintasi direktori saat ini dan direktori di bawahnya secara rekursif.-maxdepth 1
berarti berhenti pada kedalaman 1, yaitu jangan berulang ke subdirektori.-name '*.prj'
berarti hanya bertindak pada file yang namanya cocok dengan pola yang ditentukan. Perhatikan tanda kutip di sekitar pola: itu akan ditafsirkan olehfind
perintah, bukan oleh shell.-exec … {} +
berarti mengeksekusi perintah yang ditentukan untuk semua file. Itu memanggil perintah beberapa kali jika perlu, berhati-hatilah agar tidak melebihi batas baris perintah.mv -t ../prjshp
memindahkan file yang ditentukan ke../prjshp
. The-t
opsi digunakan di sini karena keterbatasan darifind
perintah: file yang ditemukan (disimbolkan dengan{}
) dilewatkan sebagai argumen terakhir dari perintah, Anda tidak dapat menambahkan tujuan setelah.Metode lain adalah menggunakan
rsync
.rsync -r … . ../prjshp
menyalin direktori saat ini ke dalam../prjshp
secara rekursif.--include='*.prj' --exclude='*'
artinya menyalin file yang cocok*.prj
dan mengecualikan yang lainnya (termasuk subdirektori, sehingga.prj
file dalam subdirektori tidak akan ditemukan).sumber
cp * | grep '\.prj$' ../prjshp/
tidak masuk akal, tetapi bisa menjadi valid secara sintaksis, jika*
diperluas ke daftar file dengan yang terakhir menjadi direktori (aliascp SOURCE1 SOURCE2....DEST
). Pipa itu tidak masuk akal, pasti, tetapi juga tetap secara sintaksis valid sejauh menyangkut shell - itu akandup()
deskriptor file baik-baik saja, hanya saja ujung pembaca pipa tidak akan mendapatkan data apa pun karenacp
tidak menulis apa pun .Perintah ini menyalin file satu per satu dan akan bekerja bahkan jika ada terlalu banyak untuk
*
diperluas menjadi satucp
perintah:sumber
Ada 3 poin kunci yang perlu diingat ketika menghadapi
Argument list too long
kesalahan:Panjang argumen baris perintah dibatasi oleh
ARG_MAX
variabel, yang menurut definisi POSIX adalah "... [m] panjang argumen maksimum ke fungsi exec termasuk data lingkungan" (penekanan ditambahkan) ". Artinya, ketika shell mengeksekusi -built-it command, ia harus memanggil salah satuexec()
untuk menelurkan proses perintah itu, dan di situlahARG_MAX
ikut bermain.Selain itu, nama atau jalur ke perintah itu sendiri (misalnya,/bin/echo
) memainkan peran.Perintah built-in Shell dijalankan oleh shell, yang berarti shell tidak menggunakan
exec()
kumpulan fungsi dan karenanya tidak dipengaruhi olehARG_MAX
variabel.Perintah tertentu, seperti
xargs
danfind
menyadariARG_MAX
variabel dan berulang kali melakukan tindakan di bawah batas ituDari poin-poin di atas dan seperti yang ditunjukkan dalam jawaban Kusalananda yang luar biasa pada pertanyaan terkait, hal itu
Argument list too long
juga dapat terjadi ketika lingkungan besar. Jadi dengan mempertimbangkan bahwa lingkungan masing-masing pengguna dapat bervariasi, dan ukuran argumen dalam byte relevan, sulit untuk menghasilkan satu file / argumen.Bagaimana cara mengatasi kesalahan seperti itu?
Kuncinya adalah untuk fokus bukan pada jumlah file, tetapi fokus pada apakah atau tidak perintah yang akan Anda gunakan melibatkan
exec()
keluarga fungsi dan tangensial - ruang stack.Gunakan built-in shell
Seperti dibahas sebelumnya, shell built-in kebal terhadap
ARG_MAX
batasan, yaitu hal-hal sepertifor
loop,while
loop, built-inecho
, dan built-inprintf
- semua itu akan berkinerja cukup baik.Pada pertanyaan terkait tentang menghapus file, ada solusinya:
Perhatikan bahwa ini menggunakan bawaan shell
printf
. Jika kita memanggil eksternalprintf
, itu akan melibatkanexec()
, maka akan gagal dengan sejumlah besar argumen:array bash
Menurut jawaban oleh jlliagre,
bash
tidak memberikan batasan pada array, jadi membangun array nama file dan menggunakan irisan per iterasi loop dapat dilakukan juga, seperti yang ditunjukkan dalam jawaban danjpreron :Ini, bagaimanapun, memiliki keterbatasan menjadi spesifik-bash dan non-POSIX.
Tingkatkan ruang tumpukan
Kadang-kadang Anda bisa melihat orang-orang menyarankan meningkatkan ruang stack dengan
ulimit -s <NUM>
; pada Linux, nilai ARG_MAX adalah 1/4 ruang stack untuk setiap program, yang berarti meningkatkan ruang stack secara proporsional menambah ruang untuk argumen.Menurut jawaban oleh Franck Dernoncourt , yang mengutip Linux Journal, seseorang juga dapat mengkompilasi ulang kernel Linux dengan nilai yang lebih besar untuk halaman memori maksimum untuk argumen, namun, itu lebih berfungsi daripada yang diperlukan dan membuka potensi untuk dieksploitasi seperti yang dinyatakan dalam artikel Linux Journal yang dikutip.
Hindari cangkang
Cara lain, adalah menggunakan
python
ataupython3
yang datang secara default dengan Ubuntu. Contoh python + here-doc di bawah ini, adalah sesuatu yang saya pribadi gunakan untuk menyalin direktori besar file di suatu tempat di kisaran 40.000 item:Untuk lintasan rekursif, Anda dapat menggunakan os.walk .
Lihat juga:
sumber
IMHO, alat optimal untuk menangani gerombolan file adalah
find
danxargs
. Lihatman find
. Lihatman xargs
.find
, dengan-print0
switch -nya , menghasilkanNUL
daftar-nama file yang terpisah (nama file dapat berisi karakter apa sajaNUL
atau/
) yangxargs
mengerti, menggunakan-0
switch.xargs
kemudian membangun perintah terlama yang diizinkan (nama file terbanyak, tidak ada nama file setengah di akhir) dan menjalankannya.xargs
ulangi ini sampaifind
persediaan tidak ada lagi nama file. Jalankanxargs --show-limits </dev/null
untuk melihat batasnya.Untuk mengatasi masalah Anda, (dan setelah memeriksa
man cp
untuk menemukan--target-directory=
):sumber