mengapa untuk loop tidak menimbulkan kesalahan "argumen terlalu lama"?

9

Saya menemukan bahwa ini akan menimbulkan kesalahan "argumen terlalu lama":

ls *.*

Dan ini tidak akan meningkatkannya:

for file in *.*
do
    echo $file
done

Mengapa?

lamwaiman1988
sumber
Apakah Anda menggunakan shell yang sama di kedua percobaan? Mungkin /bin/bashvs. /bin/sh(yang mungkin merupakan tautan ke dasbor)?
maxschlepzig
Ya, saya membuat percobaan dengan 10.000 file dengan nama file yang cukup panjang. "ls *" gagal dan "for f in *" berhasil.
lamwaiman1988

Jawaban:

13

Kesalahan "argumen terlalu panjang" adalah E2BIG, dinaikkan oleh execvepanggilan sistem jika ukuran total argumen (ditambah lingkungan, pada beberapa sistem) terlalu besar. The execvepanggilan adalah salah satu yang dimulai proses eksternal, khususnya loading file executable yang berbeda (ada panggilan yang berbeda, fork, untuk menjalankan proses terpisah yang kode masih dari file eksekusi yang sama). The forLoop adalah shell membangun internal, sehingga tidak melibatkan menelepon execve. Perintah ls *.*memunculkan kesalahan bukan ketika glob diperluas tetapi kapan lsdipanggil.

execvegagal dengan kesalahan E2BIGketika ukuran total argumen ke perintah lebih besar dari ARG_MAX batas . Anda dapat melihat nilai batas ini pada sistem Anda dengan perintah getconf ARG_MAX. (Mungkin Anda dapat melampaui batas ini jika Anda memiliki cukup memori; menjaga dengan ARG_MAXjaminan yang execveakan berfungsi selama tidak ada kesalahan yang tidak terkait terjadi.)

Gilles 'SANGAT berhenti menjadi jahat'
sumber
dan mengapa shell tidak memiliki batas?
lamwaiman1988
1
@ gunbuster363 execveBatasan ini ditegakkan oleh kernel, membatasi batasan karena argumen perlu disalin melalui memori kernel pada satu titik dan proses pengguna tidak dapat diizinkan untuk meminta jumlah memori shell yang sewenang-wenang. Di dalam shell, tidak ada alasan untuk memiliki batasan, apa pun yang sesuai dengan memori virtual baik-baik saja.
Gilles 'SO- stop being evil'
5

Saya kira bahwa dalam contoh pertama lsdijalankan dari bashmelalui fork/ execsistem pasangan panggilan, di satu detik, semua kerja adalah internal untuk bash.

The execpanggilan memiliki batas, kerja internal dari bashbukannya belum (atau lebih baik, memiliki batas yang berbeda yang tidak ada hubungannya dengan exec, mungkin jumlah memori yang tersedia).

enzotib
sumber
Anda dapat menemukan batas execdalam /usr/include/linux/limits.hbiasanya, didefinisikan sebagai ARG_MAX.
jw013
Jika kami menggunakan shell untuk loop, apakah menurut Anda daftar besar item akan mengkonsumsi semua RAM?
lamwaiman1988
Jawaban ini salah. Ini bukan 'internal', hanya saja batas untuk argumen dan perintah berbeda.
polinomial
5

Karena dalam kasus lsitu adalah argumen, dan jumlah argumen terbatas.

Dalam hal forsiklus, itu hanya daftar item. Tidak ada batasan (sejauh yang saya ketahui) untuk itu.

Šimon Tóth
sumber
Pasti ada batas untuk ekspansi shell. Ini sangat terkait dengan berapa banyak RAM yang Anda miliki .. Coba ini; sistem RAM 4GB saya meniup gasket sekitar 15,2 juta argumen 8-byte:for i in {00000001..20000000} ;do ((10#$i==1)) && break; done
Peter.O
4
@ Fred Saya tidak benar-benar berpikir bahwa menyebutkan RAM sebagai batasan diperlukan.
Šimon Tóth
2
Mungkin tidak diperlukan, tetapi itulah sifat komentar .. seseorang mungkin menganggapnya menarik, atau bahkan bernilai.
Peter.O
@ Fred: sebenarnya ya, jika memperluas argumen yang sangat besar adalah masalah umum, akan mungkin untuk mengimplementasikannya tanpa menyimpan semuanya dalam memori.
Matteo