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?


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).


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).


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).


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
Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.