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 satu exec()
untuk menelurkan proses perintah itu, dan di situlah ARG_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 oleh ARG_MAX
variabel.
Perintah tertentu, seperti xargs
dan find
menyadari ARG_MAX
variabel dan berulang kali melakukan tindakan di bawah batas itu
Dari 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 seperti for
loop, while
loop, built-in echo
, dan built-in printf
- semua itu akan berkinerja cukup baik.
for i in /path/to/dir/*; do cp "$i" /path/to/other/dir/; done
Pada pertanyaan terkait tentang menghapus file, ada solusinya:
printf '%s\0' *.jpg | xargs -0 rm --
Perhatikan bahwa ini menggunakan bawaan shell printf
. Jika kita memanggil eksternal printf
, itu akan melibatkan exec()
, maka akan gagal dengan sejumlah besar argumen:
$ /usr/bin/printf "%s\0" {1..7000000}> /dev/null
bash: /usr/bin/printf: Argument list too long
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 :
files=( /path/to/old_dir/*.prj )
for((I=0;I<${#files[*]};I+=1000)); do
cp -t /path/to/new_dir/ "${files[@]:I:1000}"
done
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.
# getconf reports value in bytes, ulimit -s in kilobytes
$ getconf ARG_MAX
2097152
$ echo $(( $(getconf ARG_MAX)*4 ))
8388608
$ printf "%dK\n" $(ulimit -s) | numfmt --from=iec --to=none
8388608
# Increasing stack space results in increated ARG_MAX value
$ ulimit -s 16384
$ getconf ARG_MAX
4194304
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
atau python3
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:
$ python <<EOF
> import shutil
> import os
> for f in os.listdir('.'):
> if os.path.isfile(f):
> shutil.copy(f,'./newdir/')
> EOF
Untuk lintasan rekursif, Anda dapat menggunakan os.walk .
Lihat juga: