Qual é a diferença entre `a [bc] d` (colchetes) e` a {b, c} d` (colchetes)?

28

Qual é a diferença entre a[bc]de a{b,c}d? Por que as pessoas usam a{b,c}dquando já existem a[bc]d?

Weijun Zhou
fonte
Quem disse para você usar command a[bc]d?
Jesse_b 27/04
3
Certamente tem seus usos se alguém o entende corretamente.
Weijun Zhou
7
Eu acho que simplesmente não entendo como a confusão entre os dois aconteceu.
Jesse_b 27/04
Fui perguntado explicitamente por um colega de trabalho menos familiarizado com o Linux sobre isso, embora não recentemente.
Weijun Zhou
@Jesse_b Se você apenas tentar com operações em arquivos como esse lse tentar apenas caracteres únicos, eles parecerão funcionar da mesma maneira.
Nacht - Restabelece Monica

Respostas:

43

Os dois são bem diferentes.

a[bc]dé um padrão de nome de arquivo (em shells diferentes de fish). Ele será expandido para os dois nomes de arquivos abd e acdse esses são nomes de arquivos existentes no diretório atual.

  • A [...]peça é uma expressão entre colchetes que corresponde a um único caractere dentre os listados (ou agrupa elementos quando os intervalos são incluídos). Para corresponder ao padrão a[bc]d, o caractere entre as seqüências de caracteres ae dem um nome de arquivo deve ser a bou a c.

  • Se abdexistir, mas acdnão existir, apenas expandiria para abde vice-versa.

  • Se nenhuma abd, nem acdexistir, dependendo do shell e as opções, isso provocaria um erro (original Unix sh, (t)csh, zsh, fish, bash -O failglob) e, possivelmente, sair do shell, ou deixar o unexpanded¹ padrão (Bourne-like e rc-como conchas) ou expandir a nada ( bash/zsh/yash -o nullglobalgumas versões mais antigas do fishUnix original she (t)cshse houver outros globs correspondentes no mesmo comando).

a{b,c}dé uma expansão de chave (em conchas que as suportam). Ele será expandido para as duas strings abd e acd.

  • A {...}parte é um conjunto delimitado por vírgulas de cordas (neste exemplo, em alguns concha, que também pode ser um intervalo, tais como a..kou 20..25ou mais avançados aqueles como 00..20..2ou 0..20..2%02d), e a expansão é calculado através da combinação de cada uma destas cordas com o flanqueamento cordas ae d. Essas seqüências podem ter mais de um caractere e também podem ser expansões de chaves.

  • A expansão ocorre independentemente de essas sequências corresponderem aos nomes de arquivos existentes ou não.

Se você estiver construindo cadeias, use uma expansão de chave. Se você estiver combinando nomes de arquivos, use um padrão de nome de arquivo.


¹ Nesse caso em particular, a[bc]dpode ser o nome de um arquivo existente, e é por isso que é potencialmente perigoso usar coisas como rm -f ./*.[ch]essas conchas e rm -f ./*.{c,h}é menos problemático.

Kusalananda
fonte
Obrigado por esclarecer "Se abd existe, mas o ACD não existe, ele seria expandido para abd". Eu acho que é isso que está faltando na minha resposta.
Weijun Zhou
9
Outra diferença crucial é que a{b,c}d, em , as partes be cnão precisam ser letras únicas; por exemplo ex{ten,ci}sion. Enquanto ex[tenci]sionou o que for, apenas corresponderá a uma dessas letras.
alexis
7

a[bc]dé a correspondência de padrões e faz parte do padrão POSIX. No POSIX, isso é introduzido como a "expressão de colchete padrão". Está documentado na seção 2.13 do manual

Quando não estiver entre aspas e fora de uma expressão entre colchetes, os três caracteres a seguir terão um significado especial na especificação dos padrões:

    ?
      Um ponto de interrogação é um padrão que deve corresponder a qualquer caractere.
    *
      Um asterisco é um padrão que deve corresponder a vários caracteres, conforme descrito em Padrões que correspondem a vários caracteres.
    [
      O colchete aberto deve introduzir uma expressão de colchete padrão.

A Seção 2.13.3 também menciona algo que se comporta de maneira diferente do que seria de se esperar para regexs comuns quando é usado para expansão de nome de arquivo (ênfase minha)

As regras descritas até agora em Padrões que correspondem a um único caractere e Padrões que correspondem a vários caracteres são qualificadas pelas seguintes regras que se aplicam quando a notação de correspondência de padrões é usada para expansão de nome de arquivo:

O caractere de barra em um nome de caminho deve ser correspondido explicitamente usando uma ou mais barras no padrão; não deve corresponder aos caracteres especiais asterisco ou ponto de interrogação nem por uma expressão entre parênteses. As barras no padrão devem ser identificadas antes das expressões entre colchetes; portanto, uma barra não pode ser incluída em uma expressão de colchete padrão usada para expansão de nome de arquivo. Se um caractere de barra for encontrado após um caractere de colchete aberto sem escape antes que um colchete de fechamento correspondente seja encontrado, o colchete aberto será tratado como um caractere comum. Por exemplo, o padrão "a[b/c]d"não corresponde a nomes de caminho como abdou a/d. Corresponde apenas a um nome de caminho literalmente a[b/c]d.

a{b,c}dé expansão de chaves , não está na especificação do POSIX. Aqui está a parte correspondente do manual do bash (ênfase minha):

A expansão de chaves é um mecanismo pelo qual cadeias arbitrárias podem ser geradas. Esse mecanismo é semelhante à expansão do nome do arquivo (consulte Expansão do nome do arquivo ), mas os nomes de arquivos gerados não precisam existir . Os padrões a serem expandidos entre colchetes assumem a forma de um preâmbulo opcional , seguido por uma série de cadeias separadas por vírgula ou uma expressão de sequência entre um par de chaves, seguido de um postscript opcional . O preâmbulo é prefixado para cada string contida entre chaves, e o postscript é anexado a cada string resultante, expandindo da esquerda para a direita.

De acordo com o comentário de @mosvy, isso apareceu pela primeira vez, cshmas o comportamento bashé diferente de cshe de outras conchas. Este tipo de expansão de chaves também está presente no glob(3).

Há outro tipo de expansão de chaves {a..z}que apareceu apenas após o bash3.0 e há mais adicionados no bash4.0.

Em um shell em que o globbing está ativado, execute em uma pasta vazia, o seguinte resultado é retornado

$ echo a[bc]d
a[bc]d
$ echo a{b,c}d
abd acd

Em resposta ao comentário de @ Jesse_b, se você estiver em um shell interativo e os dois se aplicarem, haverá a[bc]dmenos problemas ao digitar. Por exemplo grep pattern [ab][12].txt.

Weijun Zhou
fonte
2
A expansão da cinta não é um "basismo"; apareceu pela primeira vez csh, muito antes bash. Também está presente na função da biblioteca glob (3). A diferença é que bashele é executado antes de outras expansões: a=A; ab=A/B; ac=A/C; echo $a{b,c}funcionará no bash de maneira diferente de qualquer outro shell.
mosvy 27/04
Obrigado. Eu atualizarei a resposta.
Weijun Zhou 27/04