Saya mendapat kesan bahwa panjang maksimum satu argumen tidak menjadi masalah di sini sebanyak ukuran total array argumen keseluruhan plus ukuran lingkungan, yang terbatas pada ARG_MAX
. Jadi saya pikir sesuatu seperti yang berikut ini akan berhasil:
env_size=$(cat /proc/$$/environ | wc -c)
(( arg_size = $(getconf ARG_MAX) - $env_size - 100 ))
/bin/echo $(tr -dc [:alnum:] </dev/urandom | head -c $arg_size) >/dev/null
Dengan - 100
menjadi lebih dari cukup untuk menjelaskan perbedaan antara ukuran lingkungan di shell dan echo
prosesnya. Sebaliknya saya mendapat kesalahan:
bash: /bin/echo: Argument list too long
Setelah bermain-main sebentar, saya menemukan bahwa maksimum adalah urutan hex besarnya lebih kecil:
/bin/echo \
$(tr -dc [:alnum:] </dev/urandom | head -c $(($(getconf ARG_MAX)/16-1))) \
>/dev/null
Ketika yang minus dihapus, kesalahan kembali. Tampaknya maksimum untuk argumen tunggal sebenarnya ARG_MAX/16
dan -1
akun untuk byte nol ditempatkan di akhir string dalam array argumen.
Masalah lain adalah ketika argumen diulangi, ukuran total array argumen bisa lebih dekat ARG_MAX
, tetapi masih belum cukup:
args=( $(tr -dc [:alnum:] </dev/urandom | head -c $(($(getconf ARG_MAX)/16-1))) )
for x in {1..14}; do
args+=( ${args[0]} )
done
/bin/echo "${args[@]}" "${args[0]:6534}" >/dev/null
Menggunakan di "${args[0]:6533}"
sini membuat argumen terakhir 1 byte lebih lama dan memberikan Argument list too long
kesalahan. Perbedaan ini tidak mungkin diperhitungkan oleh ukuran lingkungan yang diberikan:
$ cat /proc/$$/environ | wc -c
1045
Pertanyaan:
- Apakah ini perilaku yang benar, atau ada bug di suatu tempat?
- Jika tidak, apakah perilaku ini didokumentasikan di mana saja? Apakah ada parameter lain yang menentukan maksimum untuk satu argumen?
- Apakah perilaku ini terbatas pada Linux (atau bahkan versi tertentu)?
- Apa yang menyebabkan perbedaan tambahan ~ 5KB antara ukuran maksimum sebenarnya dari argumen array ditambah ukuran perkiraan lingkungan dan
ARG_MAX
?
Informasi tambahan:
uname -a
Linux graeme-rock 3.13-1-amd64 #1 SMP Debian 3.13.5-1 (2014-03-04) x86_64 GNU/Linux
getconf ARG_MAX
tergantung pada saat iniulimit -s
. Setel ke tak terbatas, dan dapatkan 4611686018427387903 yang luar biasa untuk ARG_MAX.Jawaban:
Jawaban
Parameter yang menentukan ukuran maksimum untuk satu argumen adalah
MAX_ARG_STRLEN
. Tidak ada dokumentasi untuk parameter ini selain dari komentar dibinfmts.h
:Seperti yang ditunjukkan, Linux juga memiliki batas (sangat besar) pada jumlah argumen untuk suatu perintah.
Batas ukuran argumen tunggal (yang berbeda dari batas keseluruhan argumen plus lingkungan) tampaknya spesifik untuk Linux. Artikel ini memberikan perbandingan terperinci
ARG_MAX
dan setara pada sistem mirip Unix.MAX_ARG_STRLEN
dibahas untuk Linux, tetapi tidak ada yang menyebutkan setara pada sistem lain.Artikel di atas juga menyatakan bahwa
MAX_ARG_STRLEN
diperkenalkan di Linux 2.6.23, bersama dengan sejumlah perubahan lain yang berkaitan dengan maksimum argumen perintah (dibahas di bawah). Log / diff untuk komit dapat ditemukan di sini .Masih belum jelas apa yang menyebabkan perbedaan tambahan antara hasil
getconf ARG_MAX
dan ukuran maksimum yang dimungkinkan dari argumen plus lingkungan. Jawaban terkait Stephane Chazelas , menunjukkan bahwa bagian dari ruang dicatat oleh pointer ke masing-masing string argumen / lingkungan. Namun, penyelidikan saya sendiri menunjukkan bahwa pointer ini tidak dibuat di awalexecve
panggilan sistem ketika masih dapat mengembalikanE2BIG
kesalahan ke proses pemanggilan (meskipun pointer ke setiapargv
string pasti dibuat nanti).Juga, string berdekatan dalam memori sejauh yang saya bisa lihat, jadi tidak ada celah memori karena melakukan penyelarasan di sini. Meskipun sangat mungkin menjadi faktor dalam apa pun yang tidak menggunakan sampai memori tambahan. Memahami apa yang menggunakan ruang ekstra membutuhkan pengetahuan yang lebih rinci tentang bagaimana kernel mengalokasikan memori (yang merupakan pengetahuan berguna untuk dimiliki, jadi saya akan menyelidiki dan memperbarui nanti).
ARG_MAX Kebingungan
Sejak Linux 2.6.23 (sebagai hasil dari komit ini ), telah ada perubahan pada cara maksimum argumen perintah ditangani yang membuat Linux berbeda dari sistem mirip Unix lainnya. Selain menambahkan
MAX_ARG_STRLEN
danMAX_ARG_STRINGS
, hasilgetconf ARG_MAX
sekarang tergantung pada ukuran tumpukan dan mungkin berbeda dariARG_MAX
padalimits.h
.Biasanya hasil dari
getconf ARG_MAX
akan menjadi1/4
ukuran tumpukan. Pertimbangkan hal berikut dalambash
menggunakanulimit
untuk mendapatkan ukuran tumpukan:Namun, perilaku di atas sedikit diubah oleh komit ini (ditambahkan di Linux 2.6.25-rc4 ~ 121).
ARG_MAX
dilimits.h
sekarang menjabat sebagai hard batas bawah pada hasilgetconf ARG_MAX
. Jika ukuran tumpukan diatur sedemikian rupa sehingga1/4
ukuran tumpukan kurang dariARG_MAX
dalamlimits.h
, makalimits.h
nilainya akan digunakan:Perhatikan juga bahwa jika ukuran tumpukan diatur lebih rendah dari minimum yang mungkin
ARG_MAX
, maka ukuran tumpukan (RLIMIT_STACK
) menjadi batas atas ukuran argumen / lingkungan sebelumE2BIG
dikembalikan (meskipungetconf ARG_MAX
masih akan menunjukkan nilai dalamlimits.h
).Hal terakhir yang perlu diperhatikan adalah bahwa jika kernel dibangun tanpa
CONFIG_MMU
(mendukung perangkat keras manajemen memori), maka pemeriksaanARG_MAX
dinonaktifkan, sehingga batas tidak berlaku. MeskipunMAX_ARG_STRLEN
danMAX_ARG_STRINGS
masih berlaku.Bacaan lebih lanjut
ARG_MAX
(dan setara) pada sistem mirip Unix lainnya - http://www.in-ulm.de/~mascheck/various/argmax/MAX_ARG_STRLEN
bug yang disebabkan dengan Automake yang menanamkan skrip shell ke Makefiles menggunakansh -c
- http://www.mail-archive.com/[email protected]/msg05522.htmlsumber
Di
eglibc-2.18/NEWS
Di
eglibc-2.18/debian/patches/kfreebsd/local-sysdeps.diff
Di
linux/include/uapi/linux/limits.h
Dan
131072
apakah Anda$(getconf ARG_MAX)/16-1
, mungkin Anda harus mulai dari 0.Anda berurusan dengan glibc, dan Linux. Akan lebih baik untuk menambal getconf juga untuk mendapatkan nilai "benar" yang
ARG_MAX
dikembalikan.Sunting:
Untuk memperjelas sedikit (setelah diskusi singkat tapi panas)
The
ARG_MAX
konstan yang didefinisikan dalamlimits.h
, memberikan panjang max dari satu argumen lulus dengan exec.The
getconf ARG_MAX
perintah mengembalikan nilai maks cumulated ukuran argumen dan lingkungan ukuran diteruskan ke exec.sumber
eglibc-2.18/NEWS
cuplikan Anda ? Akan lebih baik untuk menyematkan ini ke versi kernel tertentu.getconf ARG_MAX
adalah tentang ukuran kumulatif arg + env (variabel di Linux baru-baru ini, lihatulimit -s
dan pertanyaan lain saya terhubung), itu bukan tentang panjang max dari arg tunggal yang ada sysconf / getconf query.Jadi @StephaneChazelas benar mengoreksi saya di komentar di bawah ini - shell itu sendiri tidak menentukan ukuran argumen maksimum yang diizinkan oleh sistem Anda, melainkan diatur oleh kernel Anda.
Seperti yang telah dikatakan beberapa orang lain, tampaknya kernel membatasi hingga 128kb ukuran argumen maksimum yang dapat Anda berikan ke proses baru dari yang lain saat pertama kali mengeksekusi. Anda mengalami masalah ini secara khusus karena banyak
$(command substitution)
subshell bersarang yang harus dijalankan di tempat dan menyerahkan keseluruhan output mereka dari satu ke yang berikutnya.Dan ini adalah tebakan liar, tetapi karena perbedaan ~ 5kb tampaknya begitu dekat dengan ukuran halaman sistem standar, kecurigaan saya adalah bahwa ia didedikasikan untuk penggunaan halaman
bash
untuk menangani subkulit yang Anda perlukan$(command substitution)
untuk akhirnya memberikan output dan / atau fungsi stack yang digunakannya dalam mengasosiasikan Andaarray table
dengan data Anda. Saya hanya bisa berasumsi tidak ada yang gratis.Saya menunjukkan di bawah ini bahwa, meskipun mungkin sedikit rumit, adalah mungkin untuk melewatkan nilai variabel shell yang sangat besar ke proses baru saat pemanggilan, selama Anda dapat mengatur untuk mengalirkannya.
Untuk melakukannya, saya terutama menggunakan pipa. Tetapi saya juga mengevaluasi susunan shell dengan
here-document
menunjuk padacat's stdin.
Hasil di bawah ini.Tapi satu catatan terakhir - jika Anda tidak membutuhkan kode portabel, saya pikir itu
mapfile
mungkin menyederhanakan pekerjaan shell Anda sedikit.Mungkin Anda bisa menggandakan ini dan kemudian melakukannya lagi jika Anda melakukannya di stream - Saya tidak cukup bodoh untuk mengetahuinya - tapi jelas itu berfungsi jika Anda mengalirkannya.
Saya memang mencoba mengubah bagian
printf
generator di baris dua menjadi:Ini juga berfungsi:
Jadi mungkin saya agak tidak sehat. Saya menggunakan
zero padding here
dan menambahkan nilai sebelumnya"$arg"
ke nilai saat ini"$arg"
. Saya mendapatkan jauh melampaui 6500 ...Dan jika saya mengubah
cat
baris agar terlihat seperti ini:Saya bisa mendapatkan jumlah byte dari
wc.
Ingat ini adalah ukuran setiap kunci dalamargs
array. Ukuran total array adalah jumlah dari semua nilai ini.sumber
echo $(tr -dc [:alnum:] </dev/urandom | head -c $(($(getconf ARG_MAX)*10))) >/dev/null
akan berjalan dengan baik. Hanya ketika Anda menggunakan perintah eksternal yang ada masalah.bash
menekannya entah bagaimana?printf
adalah builtin jadi tidak dieksekusi , dan AFAICT, Andacat
tidak diberi argumen.