Ciągle miałem ten problem: mam glob, który pasuje dokładnie do prawidłowych plików, ale powoduje Command line too long
. Za każdym razem, gdy konwertowałem go na jakąś kombinację find
i grep
która działa w konkretnej sytuacji, ale która nie jest w 100% równoważna.
Na przykład:
./foo*bar/quux[A-Z]{.bak,}/pic[0-9][0-9][0-9][0-9]?.jpg
Czy istnieje narzędzie do przekształcania globów w find
wyrażenia, których nie jestem świadomy? Czy też istnieje opcja find
dopasowania globu bez dopasowania tej samej globuli w podkatalogu (np. foo/*.jpg
Niedozwolone jest dopasowanie bar/foo/*.jpg
)?
-path
lub-ipath
.find . -path './foo*bar/quux[A-Z]/pic[0-9][0-9][0-9][0-9]?.jpg'
powinien działać - oprócz tego, że będzie pasował/fooz/blah/bar/quuxA/pic1234d.jpg
. Czy to będzie problem?echo <glob> | cat
, zakładając, że wiem o bash, echo jestOdpowiedzi:
Jeśli problem polega na tym, że pojawia się błąd, że lista argumentów jest za długa, użyj pętli lub wbudowanej powłoki. Podczas gdy
command glob-that-matches-too-much
może wystąpić błąd,for f in glob-that-matches-too-much
nie, więc możesz po prostu:Pętla może być bardzo powolna, ale powinna działać.
Lub:
(
printf
jest wbudowane w większość powłok, powyższe działa wokół ograniczeniaexecve()
wywołania systemowego)Działa również z bash. Nie jestem jednak pewien, gdzie dokładnie to jest udokumentowane.
Zarówno Vima, jak
glob2regpat()
i Pythonafnmatch.translate()
mogą konwertować globusy na wyrażenia regularne, ale oba używają również.*
do*
dopasowywania w poprzek/
.źródło
something
zeecho
powinien to zrobić.printf
- będzie szybszy niż dzwonienieecho
tysiące razy i oferuje większą elastyczność.exec
, które dotyczą poleceń zewnętrznych, takich jakcat
; ale ten limit nie dotyczy wbudowanych poleceń powłoki, takich jakprintf
.printf
jest wbudowana, a powłoki prawdopodobnie używają tej samej metody do dostarczania argumentów, której używają do wyliczania argumentówfor
.cat
nie jest wbudowany.mksh
gdzieprintf
nie jest wbudowane i powłoki takie jakksh93
gdziecat
jest (lub może być) wbudowane. Zobacz takżezargs
w,zsh
aby obejść to bez konieczności uciekania sięxargs
.find
(dla predykatów-name
/-path
standardowych) używa wzorców symboli wieloznacznych, podobnie jak globs (zauważ, że{a,b}
nie jest operatorem glob; po rozwinięciu otrzymujesz dwa globusy). Główną różnicą jest obsługa ukośników (oraz plików kropkowych i katalogów, które nie są specjalnie traktowanefind
).*
w globach nie obejmuje kilku katalogów.*/*/*
spowoduje wyświetlenie maksymalnie 2 poziomów katalogów. Dodanie-path './*/*/*'
spowoduje dopasowanie do plików o głębokości co najmniej 3 poziomów i nie przestaniefind
wyświetlać zawartości dowolnego katalogu na dowolnej głębokości.Do tego konkretnego
kilka globów, łatwo to przetłumaczyć, potrzebujesz katalogów na głębokości 3, więc możesz użyć:
(lub
-depth 3
z niektórymifind
implementacjami). Lub POSIXly:Co zagwarantowałoby, że te
*
i?
nie będą pasowały do/
postaci.(w
find
przeciwieństwie do globów odczytywałoby zawartość katalogów innych niżfoo*bar
te w bieżącym katalogu¹, a nie sortowało listy plików. Ale pomijając problem, to, co jest dopasowane[A-Z]
lub zachowanie*
/?
w odniesieniu do nieprawidłowych znaków jest nieokreślony, otrzymasz tę samą listę plików).Ale w każdym razie, jak pokazał @muru , nie trzeba uciekać się,
find
jeśli chodzi tylko o podzielenie listy plików na kilka przebiegów, aby obejść limitexecve()
wywołania systemowego. Niektóre powłoki, takie jakzsh
(zzargs
) lubksh93
(zcommand -x
) mają nawet wbudowaną obsługę tego.Z
zsh
(którego globusy mają również odpowiedniki-type f
i większość innychfind
predykatów), na przykład:(
(|.bak)
Jest to sprzeczne operator glob do{,.bak}
The(.)
glob kwalifikator jest odpowiednikiemfind
„s-type f
, dodaćoN
tam pominąć sortowania jak zfind
,D
aby to kropka pliki (nie stosuje się do tego glob))¹ Aby
find
przeszukiwać drzewo katalogów tak jak globs, potrzebujesz czegoś takiego:To jest przycinanie wszystkich katalogów na poziomie 1, z wyjątkiem
foo*bar
tych, i wszystkie na poziomie 2, z wyjątkiemquux[A-Z]
lubquux[A-Z].bak
, a następnie wybierzpic...
te na poziomie 3 (i przycinaj wszystkie katalogi na tym poziomie).źródło
Możesz napisać wyrażenie regularne dla znalezienia pasującego do twoich wymagań:
źródło
.
, dodać opcjonalny mecz dla.bak
i zmiany*
do[^/]*
nie pasuje do ścieżki jak / foo / foo / bar itd.[0-9][0-9][0-9][0-9]?
do[0-9]{3,4}
Uogólniając uwagę na moją drugą odpowiedź , jako bardziej bezpośrednią odpowiedź na twoje pytanie, możesz użyć tego
sh
skryptu POSIX do konwersji globu nafind
wyrażenie:Do użycia z jednym standardowym
sh
globem (więc nie z dwoma globami twojego przykładu, który używa interpretacji nawiasów ):(co nie ignoruje plików-kropek ani katalogów-kropek oprócz
.
i..
nie sortuje listy plików).Ten działa tylko z globs względem bieżącego katalogu, bez
.
lub ze..
składnikami. Przy odrobinie wysiłku możesz rozszerzyć go na dowolną glob, więcej niż glob ... Można to również zoptymalizować, abyglob2find 'dir/*'
nie wyglądałodir
tak samo jak wzorzec.źródło