Comportamento inesperado com eco [[: digit:]]


Respostas:


34

Porque são duas coisas diferentes. Este {1,2,3}é um exemplo de expansão de chaves . A {1,2,3}construção é expandida pelo shell , antes echomesmo de vê-lo. Você pode ver o que acontece se você usar set -x:

$ set -x
$ echo {1,2,3}
+ echo 1 2 3
1 2 3

Como você pode ver, o comando echo {1,2,3}é expandido para:

echo 1 2 3

No entanto, [[:digit:]]é uma classe de caracteres POSIX . Quando você o entrega echo, o shell também o processa primeiro, mas desta vez está sendo processado como um shell glob . funciona da mesma maneira como se você executasse, o echo *que imprimirá todos os arquivos no diretório atual. Mas [[:digit:]]é um glob de shell que irá corresponder a qualquer dígito. Agora, no bash, se um shell glob não corresponder a nada, ele será expandido para si mesmo:

$ echo /this*matches*no*files
+ echo '/this*matches*no*files'
/this*matches*no*files

Se a glob corresponder a algo, isso será impresso:

$ echo /e*c
+ echo /etc
/etc

Nos dois casos, echoapenas imprime o que o shell /etcsolicitar , mas no segundo caso, como a glob corresponde a algo ( ), é solicitado que imprima essa coisa.

Portanto, como você não possui nenhum arquivo ou diretório cujo nome consiste em exatamente um dígito (que é o [[:digit:]]que corresponderia), o globo é expandido para si mesmo e você obtém:

$ echo [[:digit:]]
[[:digit:]]

Agora, tente criar um arquivo chamado 5e executando o mesmo comando:

$ echo [[:digit:]]
5

E se houver mais de um arquivo correspondente:

$ touch 1 5       
$ echo [[:digit:]]
1 5

Isso está documentado na man bashexplicação das nullglobopções que desabilitam esse comportamento:

nullglob
    If  set,  bash allows patterns which match no files (see
    Pathname Expansion above) to expand to  a  null  string,
    rather than themselves.

Se você definir esta opção:

$ rm 1 5
$ shopt -s nullglob
$ echo [[:digit:]]  ## prints nothing

$ 

4
Veja também shopt -s failglobpara obter um comportamento mais útil semelhante ao das conchas modernas como zshou fish.
— Stéphane Chazelas

Eu concordo com Stéphane, use failglob. nullglobpode causar problemas inesperados, por exemplo, ao colar um URL que tenha um ?.
— Kevin

1
Claro, eu apenas mencionei nullglobpara demonstrar que o padrão está sendo interpretado como um globo pela casca.
— terdon

14

{1,2,3}Como expansão entre chaves , ela se expande para as palavras listadas sem levar em consideração o significado delas.

[...]é um grupo de caracteres usado na expansão do nome do arquivo (ou curinga ou glob) de maneira semelhante ao asterisco *e ao ponto de interrogação ?. Corresponde a qualquer caractere único listado ou caracteres membros de grupos nomeados, como [:digit:]se eles estivessem listados. O comportamento padrão da maioria dos shells é deixar o curinga como está se não houver arquivos correspondentes.

(Observe que você não pode realmente transformar um curinga / padrão no conjunto de seqüências de caracteres que ele corresponderia. O asterisco pode corresponder a qualquer sequência de qualquer comprimento, portanto, expandir qualquer padrão que a contenha produziria uma lista infinita de seqüências de caracteres.)

Assim:

$ bash -c 'echo [[:digit:]]'           # bash leaves it as-is
[[:digit:]]
$ zsh -c 'echo [[:digit:]]'            # zsh by default complains if no match
zsh:1: no matches found: [[:digit:]]
$ touch 1 3 d i g t
$ bash -c 'echo [[:digit:]]'           # now there are two matches
1 3                                    # note that d, i, g and t do NOT match

Mas ainda:

$ bash -c 'echo {1,2,3}'
1 2 3

Ambos são expandidos pelo shell , não importa se o comando que você está executando é ls, ou echoou rm. Observe também que, se qualquer um desses itens for citado, eles não serão expandidos:

$ bash -c 'echo "[[:digit:]]"'         # even though matching files still exist
[[:digit:]]
$ bash -c 'echo "{1,2,3}"'
{1,2,3}

Obrigado pela sua resposta, sou novo no Linux então deixe-me por favor, pergunte-lhe como eco está relacionada a arquivos 1 3, a sua função é imprimir os seus argumentos para stdout não à procura de arquivos como a meu conhecimento
— Abdallah Talaat

1
@AbdAllahTalaat isso não tem nada a ver com eco, na verdade. O shell (por exemplo, bash) "expandirá" o [[:digit:]] antes de passá-lo para echo, então echonunca o vê [[:digit:]], ele vê apenas 1 3. Você pode ver isso em ação executando, o set -xque imprimirá os comandos reais sendo executados (execute set +xpara desativá-lo novamente).
— terdon

@AbdAllahTalaat, echonão procura por arquivos, o shell o faz, antes de executar o arquivo echo.
— Ilkkachu 07/03/19

Especialmente porque acho que no DOS / Windows os utilitários expandem os curingas, não o shell. (Eu talvez
— esteja

desculpe pessoal, mudei a resposta correta para a resposta do tedron porque o comentário dele continha o significado de que bash é o que o trabalho não ecoa ... a resposta dele também continha esse significado .. todos vocês me ajudaram ... eu gostaria de poder colocar resposta correta para todas as suas respostas e comentários
— Abdallah Talaat

4

{1,2,3}(e, por exemplo, {1..3}são expansões entre chaves . Eles são interpretados pelo shell antes da execução do comando.

[[:digit:]]é um token de correspondência de padrão , mas você não o está usando em um local com arquivos que correspondam a esse padrão. Se você usar uma correspondência de padrão que não possui correspondências, ela se expandirá para si mesma:

$ echo [[:digit:]]; touch 3; echo [[:digit:]]
[[:digit:]]
3

Não, como as outras respostas indicam corretamente, o padrão é comparado aos nomes de arquivos.
— precisa
Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.