História do Bash globbing

10

Existe um motivo histórico pelo qual Bash "globbing" e expressões regulares não são idênticas? Por exemplo, acredito que em Bash [1-2]* corresponde a qualquer coisa que comece com 1 ou 2 seguido de qualquer outra coisa, enquanto que, como expressão regular, [1-2]* corresponderia apenas a uma sequência de 1s e 2s. Meus scripts Bash e REGEX foo são muito fracos e eu regularmente me deparo com problemas associados a essas diferenças, o que me deixou curioso para saber por que eles são diferentes.

    
por StrongBad 10.06.2014 / 09:20

3 respostas

11

bash foi inicialmente projetado no final dos anos 80 como um clone parcial de ksh com alguns recursos interativos do csh / tcsh.

As origens do globbing têm que ser encontradas nas primeiras conchas que ele constrói.

ksh em si é uma extensão do shell Bourne. A própria shell Bourne (lançada em 1979 no Unix V7) foi uma implementação limpa do zero, mas não partiu completamente do shell Thompson (o shell do V1 - > V6) e dos recursos incorporados do shell Mashey.

Em particular, argumentos de comando ainda eram separados por espaços em branco, | era agora o operador new pipe, mas ^ ainda era suportado como uma alternativa (e também explica por que você usa [!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 dos operadores regexp ( ^\|$ ) têm um significado especial próprio no shell.

O Thompson contava com um utilitário externo para globbing. Quando sh não encontrou * , [ ou ? s no comando, ele executaria o comando através de glob .

rm *.txt

acabaria executando o glob como:

["glob", "rm", "*.txt"]

e glob acabariam executando rm com a lista de arquivos correspondentes a esse padrão.

grep a.\*b *.txt

executaria glob como:

["glob", "grep", "a.2b", "*.txt"]

O * acima foi citado definindo o 8º bit nesse caractere, evitando que glob o trate como curinga. glob então removeria esse bit antes de chamar grep .

Para fazer o equivalente com regexps, isso seria:

regexp rm '\.txt$'

Ou:

regexp rm '^[^.].*\.txt$'

para excluir arquivos de pontos.

A necessidade de escapar dos operadores à medida que eles duplicam como caracteres especiais de shell, o fato de . , comum em nomes de arquivos ser um operador regexp, não torna 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 shells adicionaram diferentes operadores globbing. Atualmente, os ksh e zsh globs (e até certo ponto bash -O extglob que implementam um subconjunto de ksh globs) são funcionalmente equivalentes aos regexps com uma sintaxe que é menos complicada de usar com nomes de arquivos e a sintaxe atual do shell. Por exemplo, em zsh (com extensão extendedglob), você pode fazer:

echo a#.txt

se você quiser (improvável) para combinar nomes de arquivos que consistem em sequências de a seguidas por .txt . Mais fácil que echo (^a*\.txt$) (aqui usando chaves como uma maneira de isolar os operadores regex dos operadores de shell, que poderiam ter sido uma maneira que os shells pudessem lidar com isso).

echo (foo|bar|<1-20>).(#i)mpg

Para arquivos mpg (sem distinção entre maiúsculas e minúsculas) cujo nome de base é foo, bar ou um número decimal de 1 a 20 ...

ksh93 agora também pode incorporar expressões regulares (básicas, estendidas, semelhantes a perl ou "aumentadas") em seus globs (embora seja bastante bugs) e até fornece uma ferramenta para converter entre glob e regexp ( printf %R , printf %P ):

echo ~(Ei:.*\.txt)

para corresponder arquivos txt (não ocultos) com E expressões regulares xtended, caso i sem sensibilidade.

    
por 10.06.2014 / 14:44
8

Idiomas regulares foram introduzidos por Kleene em 1956. O artigo original não tinha a notação moderna completa para expressões regulares, mas introduziu a "estrela de Kleen": A* significa “qualquer número de repetições de A ”. Na próxima década, algumas notações mais ou menos padrão surgiram, em particular . para um caractere arbitrário e ? para significar que o caractere anterior é opcional.

A notação globalizadora de Bash deriva do glob comando apresentado em < a href="http://man.cat-v.org/unix-1st/1/glob"> Unix v1 em 1971. Na época, a globbing era realizada por um programa separado; mais tarde foi movido para o shell. O comando inicial glob tem ? para significar "qualquer caractere" e * para "qualquer sequência de caracteres". Eu não sei porque os personagens foram escolhidos; ? é bastante intuitivo e * pode ter sido inspirado em expressões regulares.

Globbing não se destinava a ser tão geral quanto expressões regulares, e expressões regulares não eram muito difundidas na época, então não havia nenhum chamado para unificar os conceitos. Desde o início, houve incompatibilidades sintáticas, com ? , . e * significando coisas diferentes em padrões de nomes de arquivos e em expressões regulares.

Os shells modernos, como o bash, expandem os padrões glob, mas foi a evolução gradual mantendo a compatibilidade com versões anteriores. Ksh88 (a versão de 1988 do shell Korn ) introduziu uma sintaxe estendida para padrões de shell, que não poderia ter a mesma sintaxe expressões regulares usuais, mas foi strongmente inspirado por ele: *(PATTERN) significa qualquer número de repetições de PATTERN , @(PATTERN1|PATTERN2) para significar " PATTERN1 or PATTERN2 ", etc.

Versões modernas do bash (desde 2.02) suportam padrões estendidos do ksh88, se você emitir shopt -s extglob primeiro.

    
por 11.06.2014 / 03:41
1

Razão histórica: SIM. Referência:
link

Só para mostrar a divergência, aqui está um exemplo bom e fácil: a*

  • shell globbing: significa que o primeiro caractere é a e, em seguida, o que quer que seja (a, ab, abca ...)
  • regex: o significado é, zero ou mais repetições de caractere a (a, aa, aaa ...)

Eu concordaria prontamente que essa discrepância de significado é muito confusa para novos usuários.

A globalização é talvez mais fácil de entender para os recém-chegados, mas também é uma construção menos poderosa.

    
por 10.06.2014 / 14:23