dlaczego for loop nie zgłasza błędu „zbyt długi argument”?

9

Odkryłem, że spowodowałoby to błąd „zbyt długi argument”:

ls *.*

I to by go nie podniosło:

for file in *.*
do
    echo $file
done

Dlaczego?

lamwaiman1988
źródło
Czy używałeś tej samej powłoki w obu eksperymentach? Może /bin/bashvs. /bin/sh(który może być linkiem do myślnika)?
maxschlepzig
Tak, przeprowadziłem eksperyment z 10000 plikami o nazwie pliku, które są dość długie. „ls *” nie powiodło się i „for f in *” powiodło się.
lamwaiman1988

Odpowiedzi:

13

Błąd „zbyt długi argument” jest E2BIGwywoływany przez execvewywołanie systemowe, jeśli całkowity rozmiar argumentów (plus środowisko, w niektórych systemach) jest zbyt duży. execveWezwanie jest ten, który rozpoczyna procesów zewnętrznych, a konkretnie ładuje inny plik wykonywalny (jest inna rozmowa, forkna prowadzenie oddzielnego procesu, którego kod jest nadal z tego samego pliku wykonywalnego). forPętli wewnętrzna konstrukcja płaszcza tak, że nie obejmuje wywołanie execve. Polecenie ls *.*podnosi błąd nie po rozwinięciu globu, ale po lswywołaniu.

execvekończy się błędem, E2BIGgdy całkowity rozmiar argumentów polecenia jest większy niż ARG_MAX limit . Możesz zobaczyć wartość tego limitu w swoim systemie za pomocą polecenia getconf ARG_MAX. (Możliwe, że możesz przekroczyć ten limit, jeśli masz wystarczającą ilość pamięci; utrzymywanie poniżej ARG_MAXgwarancji, które execvebędą działać, dopóki nie wystąpi niepowiązany błąd).

Gilles „SO- przestań być zły”
źródło
i dlaczego Shell nie miał limitu?
lamwaiman1988
1
@ gunbuster363 execveLimit jest egzekwowany przez jądro, nakłada ograniczenia, ponieważ argumenty muszą zostać skopiowane przez pamięć jądra w jednym punkcie, a procesy użytkownika nie mogą żądać dowolnej ilości pamięci powłoki. Wewnątrz powłoki nie ma powodu, aby mieć limit, wszystko, co mieści się w pamięci wirtualnej, jest w porządku.
Gilles „SO- przestań być zły”
5

Przypuszczam, że w pierwszym przykładzie lsjest wykonywana bashprzez wywołanie systemowe fork/ execpair, w drugim cała praca jest wewnętrzna bash.

execWezwanie ma swoje granice, wewnętrzny roboczy bashzamiast nie ma (albo lepiej, ma różne ograniczenia, które nie mają nic wspólnego z exec, być może ilość dostępnej pamięci).

enzotib
źródło
Można znaleźć granicę, aby execw /usr/include/linux/limits.hzazwyczaj zdefiniowany jako ARG_MAX.
jw013,
Jeśli użyjemy powłoki dla pętli, czy myślisz, że duża lista przedmiotów zajmie całą pamięć RAM?
lamwaiman1988
Ta odpowiedź jest niepoprawna. To nie jest „wewnętrzne”, po prostu granice argumentów i poleceń są różne.
wielomian
5

Ponieważ w tym przypadku lsjest to argument, a liczba argumentów jest ograniczona.

W przypadku forcyklu jest to tylko lista pozycji. Nie ma żadnych ograniczeń (o ile mi wiadomo).

Šimon Tóth
źródło
Zdecydowanie istnieje limit rozszerzania powłoki. Jest to bardzo związane z ilością dostępnej pamięci RAM. Spróbuj tego; mój system 4 GB RAM wysadza uszczelkę około 15,2 miliona 8-bajtowych argumentów:for i in {00000001..20000000} ;do ((10#$i==1)) && break; done
Peter.O
4
@fred Naprawdę nie sądziłem, że trzeba wspomnieć o RAM jako limicie.
Šimon Tóth
2
Może to nie być potrzebne, ale taka jest natura komentarzy. Ktoś może uznać to za interesujące, a nawet wartościowe.
Peter.O
@fred: właściwie tak, jeśli częstym problemem jest rozwijanie bardzo dużych argumentów, można je zaimplementować bez przechowywania wszystkiego w pamięci.
Matteo