Multidigitowe zakresy plików w porządku leksykograficznym w zsh

24

Chciałbym określić zakres plików (w porządku leksykograficznym) z dwiema liczbami całkowitymi (np. 2 do 57) w zsh przez globbing.

Na przykład: „wybierz pliki od 2 do 57 w porządku leksykograficznym pod ścieżką, która pasuje do pewnego wzorca globowania”.

Myślałem, że wystarczy nawias kwadratowy

 for x in /foo/bar/*[2-57]; do print $x; done

ale zsh najwyraźniej myśli Pytam dla plików 2do 5(lub coś podobnego) zamiast plików 2do 57. Jakieś myśli dlaczego? Jak mogę to osiągnąć?

Amelio Vazquez-Reina
źródło

Odpowiedzi:

30

[2-57]Jest to zestaw znaków składający się z 2, 3, 4, 5i 7, w zsh i każdego innego zamiennika i składni regexp tam. Twój wzorzec globu *[2-57]pasuje do każdej nazwy pliku, którego ostatnim znakiem jest jedna z tych pięciu cyfr.

Myślę, że źle pamiętasz składnię [m,n] kwalifikatora glob . Kwalifikatory glob zawsze znajdują się w nawiasach na końcu wzorca, a separatorem zakresu jest przecinek. Wzór *([2,57])rozwija się do 2., 3.,…, 57. dopasowania. Domyślna kolejność rozwijania jest leksykograficzna (z pewną specjalną magią do sortowania liczb w kolejności numerycznej, jeśli numeric_glob_sortopcja jest ustawiona); możesz kontrolować to za pomocą kwalifikatora olub Oglob (np. *(om[2,57])aby dopasować 57 najnowszy plik oprócz jednego najnowszego pliku).

for x in /foo/bar/*([2,57]); do print $x; done

Nie to, o co prosiłeś, ale powiązane i być może przydatne dla przyszłych czytelników: jeśli chcesz wyliczyć pliki od 2 do 57, czy istnieją, czy nie, możesz użyć wyrażenia nawiasowego zakresu . Ta funkcja istnieje również w bash i ksh.

echo hello{2..57}

A jeśli chcesz dopasować pliki, których nazwa zawiera liczbę od 2 do 57, możesz użyć wzorca <2-57>. Jest to specyficzne dla Zsh.

$ ls
file1 file2 file3 file57 file58
$ echo file<2-57>
file2 file3 file57

Pamiętaj, że podobny wzór *<2-57>prawdopodobnie nie spełni oczekiwań, ponieważ *może również pasować do cyfr. Na przykład file58dopasowania *<2-57>, z file5dopasowaniem *części i 8dopasowaniem <2-57>części. Wzór *[^0-9]<2-57>pozwala uniknąć tego problemu.

Gilles „SO- przestań być zły”
źródło
Masz rację. Źle pamiętałem kwalifikator globalny. Dzięki za dokładne wyjaśnienie.
Amelio Vazquez-Reina,
Nawiasem mówiąc, to stwierdzenie dostał mi trochę zdezorientowany: if you want to enumerate files 2 to 57 whether they exist or not, you can use a range brace expression. Jeśli pliki nie istnieją i nie ma żadnych dopasowań, w jaki sposób rozszerzenie nawiasów wiedziałoby, jak rozwinąć? (w jaki sposób miałby się rozszerzyć inaczej niż kwalifikator globalny?)
Amelio Vazquez-Reina,
2
@intrpc foo{8..11}barrozwija się do foo8bar foo9bar foo10bar foo11bar. Ten fragment rozszerzenia nie jest związany z nazwami plików. Podobnie foo{eight,nine,ten,eleven}barrozwija się do fooeightbar fooninebar footenbar fooelevenbar. Jest to rozszerzenie nawiasu klamrowego w ksh / bash / zsh.
Gilles 'SO - przestań być zły'
6

ale zsh najwyraźniej myśli, że proszę o pliki od 2 do 5 (lub coś w tym rodzaju) zamiast plików od 2 do 57. Jakieś myśli dlaczego?

Ponieważ []nawiasy oznaczają listę pasujących znaków (które mogą być cyframi), a nie liczby interpretowane matematycznie. Taki wzór jest dopasowywany do jednego znaku. Lista może zawierać zakresy, ale cyfr lub liter. [2-57]dopasowanie rozwija się do „Wszystkie cyfry z zakresu od 2 do 5 i 7” .

Aby dopasować liczby od 2 do 57, łatwiej byłoby użyć wyrażenia sekwencji zamiast wzorca globowania (lub łącznie z takim):

for x in /foo/bar/*{2..57}; do print $x; done

Edycja : Ale to niestety nie da ci uporządkowania leksykograficznego wszystkich wymienionych plików - zostaną one pogrupowane według wspólnych numerów kończących się z powodu rozszerzenia powłoki.

rozcietrzewiacz
źródło
Dzięki @rozcietrzewiacz! Powinienem o tym pomyśleć. W moich plikach były liczby, więc przez chwilę myślałem, że []drukuję rzeczy w porządku ...
Amelio Vazquez-Reina,
Twoje wyjaśnienie [2-57]jest poprawne, ale nie sądzę {2..57}(to miałeś na myśli, prawda?) Jest istotne dla tego, co intrpc chce zrobić, czyli „wybierz pliki od 2 do 57 w porządku leksykograficznym”.
Gilles 'SO - przestań być zły'
Dzięki za edycję (chyba czas na sen). I masz rację - zapomniałem o części porządku leksykograficznego .
rozcietrzewiacz 19.11.11