Jump to content

Expansões do shell


fredericopissarra

Recommended Posts

Recentemente postei uma pegadinha no Discord:

$ cd ~/Temp # Diretório vazio!
$ echo TESTE | tr [:upper:] [:lower:]
teste

As sequências [:upper:] e [:lower:] não são regular expressions, mas atalhos derivados das funções em ctype.h, do C (embora essas "classes" de caracteres existam, também, no padrão estendido POSIX de regexes). Note que a tradução (tr) faz exatamente o que mandamos fazer: Converte caracteres maiúsculos (uppercase) para minúsculos (lowercase). Mas veja isso:

$ touch l # cria arquivo 'l', vazio.
$ echo TESTE | tr [:upper:] [:lower:]
lllll

Um amigo topou com isso e eu testei, achando que era algum bug na distro dele... Ué? Mas não é que o troço acontece mesmo? Por quê?

O que acontece aqui é que os colchetes '[' e ']' são também usados pelo shell para especificar caracteres, num nome de arquivo. Por exemplo. Se você quiser listar todos os arquivos que comecem com a letra 'L' (maiúsculo e minúsculo), pode fazer algo assim:

$ ls [Ll]*

Esse '[Ll]*' é expandido pelo shell para todos os nomes de arquivos/diretórios que ele encontrar que atendam ao critério. Assim, [:lower:], sem as aspas, segue o mesmo princípio... Se existirem arquivos de 1 único caracter, cujo nome seja ':', 'l', 'o', 'w', 'e' ou 'r', o shell vai expandir o argumento para todos os arquivos que encontrar. É como se o comando, no exemplo acima, fosse:

$ echo TESTE | tr [:upper:] l

Se criarmos um arquivo 'r', teremos:

$ touch r
$ echo TESTE | tr r l r

E você obtererá um erro no uso de 'tr' (porque tem um argumento extra que não deveria estar lá). Se apagar o 'l':

$ rm l
$ echo TESTE | tr [:upper:] [:lower:] # o mesmo que 'tr r r'
TESTE

O que faltou para evitar essas expansões é colocar os argumentos entre aspas:

$ echo TESTE | tr '[:upper:]' '[:lower:]' # Não apaguei 'r'! :)
teste

Com relação à expansão pelo shell, você pode fazer um teste simples:

/* test.c */
#include <stdio.h>

int main( int argc, char *argv[] )
{
  while ( *++argv ) printf( "Arg: \"%s\"\n", *argv );
}

Compilando e executando:

$ cc -o test test.c
$ touch l o w e r # cria os arquivos 'l', 'o', 'w', 'e' e 'r'.
$ ./test [:lower:]
Arg: "e"
Arg: "l"
Arg: "o"
Arg: "r"
Arg: "w"
$ ./test '[:lower:]'
Arg: "[:lower:]"

[]s
Fred

Link to comment
Share on other sites

Archived

This topic is now archived and is closed to further replies.

  • Recently Browsing   0 members

    • No registered users viewing this page.
×
×
  • Create New...