Existe uma razão histórica pela qual as expressões regulares e "regulares" do Bash não são idênticas? Por exemplo, acredito que no Bash [1-2]*
corresponde a qualquer coisa que comece com 1 ou 2 seguido por qualquer outra coisa, enquanto uma expressão regular [1-2]*
corresponderia apenas a uma sequência de 1s e 2s. Meus scripts Bash e REGEX foo são bastante fracos e eu regularmente encontro problemas associados a essas diferenças, o que me deixou curioso para saber por que elas são diferentes.
shell
regular-expression
wildcards
history
StrongBad
fonte
fonte
rm -- ^[^.].*\.txt$
vez derm -- *.txt
?find . -regex ".*\.txt$" | xargs rm --
ourename
para renomear arquivos (ésed
para nomes de arquivos), cuidado com o fato de que alguns sistemas têm uma aparência diferenterename
.^[^.].*\.txt$
deveria levar em consideração a ignorância dos arquivos de ponto. Note que o-regex
é um extensões GNU, alguns escudos como ksh93 ou zsh pode incorporar regexps em suas bolhas (tente por exemplo:ksh93 -c 'echo ~(E:^[^.].*\.txt$)'
)Respostas:
bash
foi inicialmente projetado no final dos anos 80 como um clone parcial deksh
alguns recursos interativos do csh / tcsh.As origens do globbing devem ser encontradas nas conchas anteriores nas quais se baseia.
ksh
em si é uma extensão do shell Bourne. O próprio shell Bourne (lançado pela primeira vez em 1979 no Unix V7) foi uma implementação limpa do zero, mas não se afastou completamente do shell Thompson (o shell V1 -> V6) e incorporou recursos do shell Mashey.Em particular, os argumentos de comando ainda estavam separados por espaços em branco,
|
agora era o novo operador de canal, mas^
ainda era suportado como uma alternativa (e também explica por que você faz[!a-z]
e não[^a-z]
),$1
ainda era o primeiro argumento para um script e a barra invertida ainda era o caractere de escape . Muitos operadores regexp (^\|$
) têm um significado especial no shell.O shell Thompson contava com um utilitário externo para globbing. Quando
sh
encontrado sem aspas*
,[
ou?
s no comando, ele executaria o comandoglob
.acabaria rodando glob como:
e glob acabaria executando
rm
com a lista de arquivos que correspondem a esse padrão.funcionaria
glob
como:O
*
acima foi citado definindo o 8º bit nesse caractere, impedindoglob
de tratá-lo como um curinga.glob
removeria esse bit antes de ligargrep
.Para fazer o equivalente a regexps, isso teria sido:
Ou:
excluir arquivos de ponto.
A necessidade de escapar dos operadores, pois eles dobram como caracteres especiais do shell, o fato de que
.
, comum nos nomes de arquivos, é um operador regexp, não é muito apropriado combinar nomes de arquivos e complicado para um iniciante. Na maioria dos casos, tudo o que você precisa são curingas que possam substituir um (?
) ou qualquer número (*
) de caracteres.Agora, diferentes invólucros adicionaram diferentes operadores de globbing. Atualmente, os globs ksh e zsh (e até certo ponto
bash -O extglob
que implementam um subconjunto de globs ksh) são funcionalmente equivalentes aos regexps com uma sintaxe menos trabalhosa para usar com nomes de arquivos e a sintaxe atual do shell. Por exemplo, emzsh
(com extensão extendedglob), você pode:se você deseja (improvável) corresponder a nomes de arquivos que consistem em sequências de
a
seguidas por.txt
. Mais fácil do queecho (^a*\.txt$)
(aqui, usar chaves como uma maneira de isolar os operadores regex dos operadores de shell, que poderiam ter sido uma das maneiras pelas quais os shells poderiam lidar com isso).Para arquivos mpg (sem distinção entre maiúsculas e minúsculas) cujo nome base é foo, bar ou um número decimal de 1 a 20 ...
ksh93
agora também pode incorporar regexps (básico, estendido, parecido com perl ou "aumentado") em seus globos (embora seja bastante complicado) e até fornece uma ferramenta para converter entre glob e regexp (printf %R
,printf %P
):de jogo (não oculto) txt arquivos com E Xtended expressões regulares, distinção entre maiúsculas i nsensitively.
fonte
~(opt:pat)
para nenhuma das opções em maiúsculas. Talvezprint -r -- ~(Ei).*\.txt$
. Colocar o padrão dentro parece ser útil apenas para evitar ter que ativar e desativar uma opção para parte de um padrão. Estranhamente, você pode misturar e combinar vários idiomas padrão dentro do mesmo globo.~(Ki)*.~(E)txt$
é equivalente. (No final, tudo é convertido em regex e passado para o mecanismo de regex da libast internamente).~(Ei:.*\.txt)
funciona para mim mesmo com versões de 15 anos como o ksh93 o +.~(E)x
e~(E:x)
é que o último está ancorado (correspondex
apenas enquanto o anterior corresponde a qualquer coisa que contenhax
), que pode ser o tipo de problema em que você se deparou (o uso~(-lr)~(E:x)
para remover a ancoragem~(E-lr:x)
não funciona). De qualquer forma, eu concordo que é bem complicado, mesmo na versão mais recente.Linguagens regulares foram introduzidas por Kleene em 1956. O artigo seminal não possuía a notação moderna e completa para expressões regulares, mas introduziu a “estrela Kleen”:
A*
significando “qualquer número de repetições deA
”. Na década seguinte, surgiram algumas notações mais ou menos padronizadas, em particular.
para um caráter arbitrário e?
para significar que o caractere anterior é opcional.A notação de glamour de Bash deriva do
glob
comando introduzido no Unix v1 em 1971. Na época, o globbing era realizado por um programa separado; mais tarde foi movido para dentro da concha. Oglob
comando inicial deve?
significar "qualquer caractere" e*
"qualquer sequência de caracteres". Não sei por que os personagens foram escolhidos;?
é bastante intuitivo e*
pode ter sido inspirado em expressões regulares.O globbing não tinha a intenção de ser tão geral quanto as expressões regulares, e as expressões regulares não eram muito difundidas na época, portanto não havia necessidade de unificar os conceitos. Desde o início, havia incompatibilidades sintáticas, com
?
,.
e*
que significa coisas diferentes em padrões de nome de arquivo e em expressões regulares.Os reservatórios modernos, como o bash, se expandem nos padrões glob, mas a evolução gradual mantém a compatibilidade com versões anteriores. O Ksh88 (a versão de 1988 do shell Korn ) introduziu uma sintaxe estendida para padrões de shell, que não podia ser a mesma sintaxe das expressões regulares usuais, mas foi fortemente inspirada por ele:
*(PATTERN)
significar qualquer número de repetições dePATTERN
,@(PATTERN1|PATTERN2)
significar "PATTERN1
ouPATTERN2
", etc.As versões modernas do bash (desde a versão 2.02) suportam os padrões estendidos do ksh88, se você emitir
shopt -s extglob
primeiro.fonte
extglob
opção foi introduzida no bash 2.02 em torno de 1998. O Zsh adquiriuksh_glob
na série 3.1 em algum momento na mesma época. O Zsh possui muitas extensões de globbing próprias (algumas exigindo aextended_glob
opção).bash
, ao contrário doksh
extglob, o basgl não é compatível com POSIX porque não está desabilitado nas variáveis. Emksh
,var='@(*)'; echo $var
expande para todos os nomes de arquivo no diretório atual que iniciam@(
e terminam)
como o POSIX exige, enquantobash -O extglob
expande para todos os arquivos. (ainda assim, pode-se considerar que o comportamento do bash faz mais sentido aqui (e o comportamento do ksh é bastante doloroso quando você deseja ter padrões em variáveis)). Essa sintaxe glob é tão estranha por causa disso (compatibilidade POSIX / Bourne). Compare com os globs estendidos do zsh.Razão histórica: SIM. Referência:
http://en.wikipedia.org/wiki/Glob_(programming)#Origin
Apenas para mostrar a divergência, aqui está um exemplo bom e fácil:
a*
a
e depois o que for (a, ab, abca ...)a
(a, aa, aaa ...)Eu concordaria prontamente que essa discrepância de significado é muito confusa para novos usuários.
O globbing é talvez mais fácil de entender para os novatos, mas também é uma construção menos poderosa.
fonte