Jump to content
Sign in to follow this  
fredericopissarra

Expansões do shell

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

Share this post


Link to post
Share on other sites

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.

Guest
Reply to this topic...

×   Pasted as rich text.   Paste as plain text instead

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

Sign in to follow this  

  • Recently Browsing   0 members

    No registered users viewing this page.

×
×
  • Create New...