Por que colchetes impedem a expansão do shell?

3

'4800483343' é um diretório e 'file1' & 'file2' são dois arquivos.

Por que acontece o seguinte?

$ ls 4800483343
file1 file2

$ md5sum 4800483343/*
36468e77d55ee160477dc9772a99be4b  4800483343/file1
29b098f7d374d080eb006140fb01bbfe  4800483343/file2

$ mv 4800483343 4800[48]3343

$ md5sum 4800[48]3343/*
md5sum: 4800[48]3343/*: No such file or directory

$ md5sum '4800[48]3343'/*
36468e77d55ee160477dc9772a99be4b  4800[48]3343/file1
29b098f7d374d080eb006140fb01bbfe  4800[48]3343/file2

Quais outros personagens causam isso?

    
por EmmaV 16.10.2015 / 04:42

3 respostas

5

Resposta para a pergunta original

Why are square brackets preventing shell expansion

Os colchetes não impedem a expansão do shell, mas as cotações fazem.

Eu suspeito que os comandos que você executou foram os seguintes

Isso executa o md5sum nos arquivos em dir/ :

$ md5sum d[i]r/*
02fdd7309cef4d392383569bffabf24c  dir/file1
db69ce7c59b11f752c33d70813ab5df6  dir/file2

Isso move dir para d[i]r com as aspas impedindo a expansão dos colchetes:

$ mv dir 'd[i]r'

Isso procura o diretório dir que não existe mais:

$ md5sum d[i]r/*
d[i]r/*: No such file or directory

Por causa das aspas, a aparência a seguir está no novo diretório chamado d[i]r :

$ md5sum 'd[i]r'/*
02fdd7309cef4d392383569bffabf24c  d[i]r/file1
db69ce7c59b11f752c33d70813ab5df6  d[i]r/file2

Resposta para a pergunta revisada

Na pergunta revisada, o diretório 4800483343 existe e o seguinte comando é executado:

mv 4800483343 4800[48]3343

O que acontece quando este comando é executado depende se o glob 4800[48]3343 corresponde a qualquer diretório existente. Se nenhum diretório corresponder a isso, então 4800[48]3343 se expande para si mesmo 4800[48]3343 e o diretório 4800483343 é movido para o diretório 4800[48]3343 .

Consequentemente:

  1. O comando md5sum 4800[48]3343/* retornará o erro "Nenhum arquivo ou diretório", porque não existe nenhum diretório que corresponda ao glob 4800[48]3343 .

  2. O comando md5sum '4800[48]3343'/* localizará corretamente os arquivos porque as citações impedem a expansão do glob.

Exemplos de globs

Vamos criar dois arquivos:

$ touch a1b a2b

Agora, observe estes globs:

$ echo a[123]b
a1b a2b
$ echo a?b
a1b a2b
$ echo *b
a1b a2b
    
por 16.10.2015 / 04:56
3

Uma expressão de colchetes representa qualquer número de caracteres simples que podem corresponder a uma posição de caractere única . Essa regra simples tende a ficar confusa quando você começa a lidar com caracteres de multibyte e [[. collating elements .]] e / ou [[= equivalence =]] classes, mas há muitos programas que não suportam totalmente partidas multi-char para aqueles ainda de qualquer maneira. E os dígitos ASCII de 0 a 9 são bastante seguros de que as apostas sempre coincidem entre si e agrupadas na ordem em uma expressão de colchetes para basicamente qualquer localidade. POSIX, pelo menos, requer que esse último bit seja verdadeiro.

Por exemplo:

cd /tmp
for d in 0 1 2 3 4 5 6 7 8 9; do mkdir "$d"; done
ls [0123]
0:

1:  

2:

3:

Basicamente, uma única expressão% bracket [ ] shell glob é simplesmente uma% mais específica? any char glob.

echo ?/; echo [2468]/
0/ 1/ 2/ 3/ 4/ 5/ 6/ 7/ 8/ 9/
2/ 4/ 6/ 8/

E assim, o shell glob 4800[48]3343 corresponderá a um dos dois nomes de arquivos de diretório atuais a seguir:

480043343
480083343

... mas não irá corresponder ...

4800483343
4800843343
4800[48]3343

Se você quiser usar os colchetes literais nos seus nomes de arquivos, poderá corresponder aos que estão entre as expressões de colchetes:

touch 4800\[48]3343
echo 4800[[]48[]]3343
4800[48]3343

Os globs de colchetes do shell também não são muito citados. Existem três caracteres que o shell reconhecerá em um contexto de lista como o início de uma expressão glob:

* ? [

O colchete direito sem o colchete esquerdo à esquerda é apenas outro caractere e não precisa ser citado:

echo ]
]

Então, se você apenas citar o colchete esquerdo para qualquer par, eles sempre serão interpretados literalmente. Senão você pode desabilitar o globbing a qualquer momento, com:

set -f

Ligue-o de novo quando quiser:

set +f
    
por 16.10.2015 / 08:06
2

Se você renomeou o diretório 4800483343 to 4800[48]3343 , então você precisa escapar dos metacaracters [ ] com alguma forma de cotação. Tudo isso vai funcionar:

$ ls 4800\[48\]3343/*
$ ls "4800[48]3343"/*
$ ls '4800[48]3343'/*

Tudo irá imprimir corretamente:

4800[48]3343/file1  4800[48]3343/file2

No entanto, se você deixar os metacaracteres [ e ] sem aspas, eles serão interpretados como uma descrição de colchetes para "Expansão de nome de caminho". Pesquise o manual bash de «Expansão Pathname» e você encontrará isto:

 [...]     Matches any one of the enclosed characters. 

E mais um texto explicando como isso deve funcionar. Resumindo:

A [abc] will match ONE character, either an 'a', an 'b' or an 'c'.

Portanto, 4800[48]3343 sem aspas irá corresponder a 480043343 ou 480083343 .
Nenhum dos quais é o diretório: 4800[48]3343 , e nenhuma expansão será feita por: ls 4800[48]3343/* como nenhum diretório foi encontrado. Uma expansão mais complexa corresponderá ao diretório e a expansão funcionará:

$ ls 4800$'3'[48][48]$'5'3343/*

Mas provavelmente aqui estou me aprofundando muito nessa questão: -)

    
por 16.10.2015 / 21:42