Czy istnieje historyczny powód, dla którego Bash „globbing” i wyrażenia regularne nie są identyczne? Na przykład uważam, że w Bash [1-2]*
dopasowuje wszystko, co zaczyna się od 1 lub 2, po których następuje cokolwiek innego, podczas gdy jako wyrażenie regularne [1-2]*
pasowałoby tylko do sekwencji 1 i 2. Moje skrypty Bash i REGEX foo są dość słabe i regularnie spotykam się z problemami związanymi z tymi różnicami, co mnie ciekawiło, dlaczego się różnią.
shell
regular-expression
wildcards
history
StrongBad
źródło
źródło
rm -- ^[^.].*\.txt$
zamiast tegorm -- *.txt
?find . -regex ".*\.txt$" | xargs rm --
lub,rename
aby zmienić nazwę plików (dotyczysed
nazw plików), strzeż się, że niektóre systemy mają innerename
.^[^.].*\.txt$
wziąć pod uwagę ignorowanie plików kropek. Należy pamiętać, że-regex
jest to rozszerzenia GNU, niektóre muszle jak ksh93 lub zsh mogą zawierać wyrażeń regularnych w swoich globs (spróbuj na przykład:ksh93 -c 'echo ~(E:^[^.].*\.txt$)'
)Odpowiedzi:
bash
został pierwotnie zaprojektowany pod koniec lat 80. jako częściowy klonksh
z niektórymi interaktywnymi funkcjami csh / tcsh.Początki globowania należy znaleźć we wcześniejszych powłokach, na których się opiera.
ksh
sam jest przedłużeniem powłoki Bourne'a. Sama powłoka Bourne'a (po raz pierwszy wydana w 1979 roku w Unixie V7) była czystą implementacją od zera, ale nie odbiegała całkowicie od powłoki Thompson (powłoka V1 -> V6) i zawierała funkcje z powłoki Mashey.W szczególności argumenty poleceń były nadal oddzielone spacjami,
|
był teraz nowym operatorem potoku, ale^
nadal był obsługiwany jako alternatywa (a także wyjaśnia, dlaczego tak robisz,[!a-z]
a nie[^a-z]
),$1
był nadal pierwszym argumentem skryptu, a ukośnik odwrotny był nadal znakiem ucieczki . Tak wiele operatorów wyrażeń regularnych (^\|$
) ma specjalne znaczenie w powłoce.Powłoka Thompsona opierała się na zewnętrznym narzędziu do globowania. Kiedy
sh
znaleziono cytowane*
,[
lub?
S w poleceniu, by go uruchomić poprzez polecenieglob
.skończyłby z globem jako:
a glob skończyłby
rm
z listą plików pasujących do tego wzorca.działałby
glob
jako:*
Powyżej zostały podane przez ustawienie 8th trochę na tym charakterze, zapobiegającglob
od traktując go jako zamiennika.glob
usunie ten bit przed zadzwonieniemgrep
.Aby zrobić odpowiednik wyrażeń regularnych, byłoby to:
Lub:
aby wykluczyć pliki kropkowe.
Konieczność ucieczki przed operatorami, ponieważ podwajają się one jako znaki specjalne powłoki, fakt, że
.
często w nazwach plików jest operatorem wyrażenia regularnego, sprawia, że dopasowanie nazw plików nie jest zbyt odpowiednie i skomplikowane dla początkującego. W większości przypadków potrzebujesz tylko symboli wieloznacznych, które mogą zastąpić jeden (?
) lub dowolną liczbę (*
) znaków.Teraz różne powłoki dodały różnych operatorów globowania. Obecnie globusy ksh i zsh (i do pewnego stopnia
bash -O extglob
implementujące podzbiór globów ksh) są funkcjonalnie równoważne wyrażeniom regularnym z składnią, która jest mniej kłopotliwa w użyciu z nazwami plików i bieżącą składnią powłoki. Na przykład wzsh
(z rozszerzeniem rozszerzonymglob) możesz:jeśli chcesz (mało prawdopodobne), aby dopasować nazwy plików składające się z sekwencji
a
po których następuje.txt
. Łatwiej niżecho (^a*\.txt$)
(tutaj użycie nawiasów klamrowych jako sposobu odizolowania operatorów wyrażeń regularnych od operatorów powłoki, które mogłyby być jednym ze sposobów, w jaki powłoki mogłyby sobie z tym poradzić).Dla plików mpg (bez rozróżniania wielkości liter), których basename to foo, bar lub liczba dziesiętna od 1 do 20 ...
ksh93
teraz może również zawierać wyrażenia regularne (podstawowe, rozszerzone, podobne do Perla lub „rozszerzone”) w swoich globach (chociaż jest dość błędne), a nawet zapewnia narzędzie do konwersji między glob i regexp (printf %R
,printf %P
):do meczu (nie ukryte) txt plików z E Xtended wyrażeń regularnych, CASE- I nsensitively.
źródło
~(opt:pat)
żadnej z wielkich liter. Możeprint -r -- ~(Ei).*\.txt$
. Umieszczenie wzoru w środku wydaje się być przydatne tylko w celu uniknięcia konieczności włączania i wyłączania opcji dla części wzoru. Dziwne jest jednak to, że możesz mieszać i dopasowywać wiele języków wzorców w tym samym globu.~(Ki)*.~(E)txt$
jest równoważne. (Na koniec wszystko jest po prostu konwertowane na regex i przekazywane wewnętrznie do silnika regex libast).~(Ei:.*\.txt)
działa dla mnie nawet z 15-letnimi wersjami, takimi jak ksh93 o +.~(E)x
i~(E:x)
jest to, że ta ostatnia jest zakotwiczona (dopasowuje sięx
tylko, podczas gdy pierwsza dopasowuje się do wszystkiego, co zawierax
), co może być rodzajem problemu, na jaki się natknąłeś (użyj,~(-lr)~(E:x)
aby usunąć zakotwiczenie,~(E-lr:x)
nie zrobi). W każdym razie zgadzam się, że jest dość wadliwy, nawet w najnowszej wersji.Języki regularne zostały wprowadzone przez Kleene w 1956 roku. Artykuł ten nie miał pełnej nowoczesnej notacji dla wyrażeń regularnych, ale wprowadził „gwiazdę Kleen”:
A*
oznaczającą „dowolną liczbę powtórzeńA
”. W następnej dekadzie pojawiły się mniej lub bardziej standardowe notacje, w szczególności.
dla dowolnych znaków i?
oznaczające, że poprzedni znak jest opcjonalny.Notacja globowania Basha wywodzi się z
glob
polecenia wprowadzonego już w Unixie v1 w 1971 roku. W tym czasie globbing był wykonywany przez osobny program; później został przeniesiony do powłoki. Wczesneglob
polecenie musi?
oznaczać „dowolny znak” i*
„dowolny ciąg znaków”. Nie wiem, dlaczego wybrano postacie;?
jest dość intuicyjny i*
mógł zostać zainspirowany tym z wyrażeń regularnych.Globbing nie miał być tak ogólny jak wyrażenia regularne, a wyrażenia regularne nie były wówczas bardzo rozpowszechnione, więc nie było wezwania do ujednolicenia pojęć. Od samego początku było składniowe niezgodności z
?
,.
i*
co oznacza różne rzeczy w wzorców nazw plików i wyrażeń regularnych.Nowoczesne powłoki, takie jak bash, rozwijają się na wzorach globów, ale była to stopniowa ewolucja z zachowaniem kompatybilności wstecznej. Ksh88 (wersja powłoki Korn z 1988 roku ) wprowadziła rozszerzoną składnię dla wzorców powłoki, która nie może być taką samą składnią jak zwykłe wyrażenia regularne, ale jest mocno przez nią zainspirowana:
*(PATTERN)
oznaczać dowolną liczbę powtórzeńPATTERN
,@(PATTERN1|PATTERN2)
oznaczać „PATTERN1
lubPATTERN2
”, itp.Nowoczesne wersje bash (od 2.02) obsługują rozszerzone wzorce ksh88, jeśli wydajesz je jako
shopt -s extglob
pierwsze.źródło
extglob
opcję wprowadzono w bash 2.02 gdzieś około 1998 roku. Zsh nabyłksh_glob
w serii 3.1 gdzieś w tym samym czasie. Zsh ma wiele własnych rozszerzeń (niektóre wymagają takiejextended_glob
opcji).bash
przeciwieństwie doksh
extglob sprawia, że bash nie jest zgodny z POSIX, ponieważ nie jest wyłączony w zmiennych. Inksh
,var='@(*)'; echo $var
rozwija się do wszystkich nazw plików w bieżącym katalogu, które zaczynają się@(
i kończą,)
jak wymaga POSIX, podczas gdy wbash -O extglob
nim rozwija się do wszystkich plików. (nadal można uznać, że zachowanie bash ma tutaj większy sens (a zachowanie ksh jest dość uciążliwe, gdy chcesz mieć wzorce w zmiennych)). Ta składnia globalna jest z tego powodu tak niewygodna (kompatybilność z POSIX / Bourne). Porównaj z rozszerzonymi globami zsh.Powód historyczny: TAK. Odniesienie:
http://en.wikipedia.org/wiki/Glob_(programming)#Origin
Aby pokazać rozbieżność, oto dobry i łatwy przykład:
a*
a
a następnie cokolwiek (a, ab, abca ...)a
(a, aa, aaa ...)Z przyjemnością zgodzę się, że ta rozbieżność znaczeń jest bardzo myląca dla nowych użytkowników.
Globbing jest być może łatwiejszy do uchwycenia dla początkujących, ale jest również mniej wydajnym konstruktem.
źródło