Aula 9 – Expansões do Shell

Aula 8 – Operações Aritméticas | Índice | Aula 10 – Expansões de Parâmetros


Seu apoio é muito importante para a criação e a manutenção dos cursos gratuitos do canal debxp:


9.1 – O que são expansões

Antes de ser executada, uma linha de comando passa por uma análise completa. Nessa análise, o shell procura por palavras, símbolos e operadores para dividir o comando em vários pedaços (chamados tokens) e determinar o que deverá ser feito com cada um deles. Em um dado momento neste processo, alguns desses pedaços serão identificados como elementos que deverão ser substituídos por algum tipo de valor, e são essas substituições que nós chamamos de expansões.

Através das suas expansões, o Bash oferece um poderoso conjunto de símbolos e elementos sintáticos que podem facilitar muito a nossa vida e tornar os nossos códigos mais limpos e rápidos.

Expansão Descrição
Expansão de caminhos Simplifica a referência a caminhos.
Expansão de nomes de arquivos Símbolos para representar padrões de caracteres nos nomes de arquivos.
Expansão de chaves Permite a geração de strings a partir de um padrão.
Substituição de comandos Permite que a saída de um comando torne-se um valor.
Expansão aritmética Efetua expressões aritméticas e disponibiliza o resultado como um valor.
Expansão de parâmetros Retorna o valor de um parâmetro (variável) e ainda oferece diversas formas de manipulá-lo.
Quebra de palavras Percorre resultados de outras expansões e decide como tratar as strings que não estão entre aspas a partir de um caractere de separação.
Remoção de aspas Remove todas as ocorrências dos caracteres \, ' e " que não resultem de uma expansão.
Substituição de processos Permite enviar a saída de um comando para a entrada de outro comando que só aceitaria arquivos como argumento. Não está disponível no shell ”sh”!

Nesta aula, nós veremos algumas das expansões de uso mais comum, e a próxima aula será totalmente dedicada à expansão de parâmetros.

Da lista acima, nós já conhecemos: as substituições de comando, as expansões
aritméticas
. Além disso, todas as expansões de variáveis escalares e vetoriais vistas até aqui são parte das chamadas expansões de parâmetros.

9.2 – Expansão de caminhos

Uma expansão de caminho acontece quando o shell interpreta o caractere til (~) como o caminho absoluto da pasta do usuário atual ou de um usuário especificado.

Exemplo 1: exibindo a pasta do usuário logado…

:~$ echo ~
/home/user

Exemplo 2: entrando na pasta ‘Documentos’ do usuário logado…

:~$ cd ~/Documentos
:~/Documentos$ pwd
/home/user/Documentos

Exemplo 3: exibindo a pasta do usuário ‘root…

:~$ echo ~root
/root

O Bourne Shell (sh) não expande o til!

9.3 – Expansão de nomes de arquivos

Na ocorrência de metacaracetres formadores de padrões de nomes de arquivos, o shell fará uma busca na lista de arquivos da pasta indicada tentando encontrar os nomes que correspondam ao padrão. Os metacaracteres são:

Meta Descrição
* Representa zero ou mais caracteres, exceto o ponto (.) no início dos nomes de arquivos ocultos.
? Representa um único caractere existente, exceto o ponto (.) no início dos nomes de arquivos ocultos.
[...] Representam um conjunto ou uma faixa de caracteres que podem ocupar uma única posição no nome do arquivo.

Exemplo 1: lista todos os arquivos com nomes terminados em ‘.txt’…

:~$ ls *.txt

Exemplo2: lista todos os arquivos que começam com o caractere ‘a’…

:~$ ls a*

Exemplo 3: lista todos os arquivos que contenham um ponto…

:~$ ls *.*

Exemplo 4: lista todos os arquivos ocultos…

:~$ ls .*

Lembre-se de que diretórios também são arquivos!

Exemplo 5: lista todos os arquivos com nomes iniciados com caracteres na faixa de ‘a’ até ‘j’…

:~$ ls [a-j]*

Exemplo 6: lista todos os arquivos que começam apenas com os caracteres ‘a’ e ‘j’…

:~$ ls [aj]*

Também é importante notar que, ao expandir nomes de arquivos, o shell está gerando uma lista de valores separados por espaço que serão passados como argumentos para o comando em uso (ls, nos exemplos). Portanto, supondo que o comando abaixo tenha encontrado três correspondências…

:~$ ls dir*

Isso seria o mesmo que…

:~$ ls dir1 dir2 dir3

O que faria o utilitário ls listar o conteúdo dessas três pastas.

Outra possibilidade interessante decorrente dessa expansão, é que não precisamos do utilitário ls para listar arquivos. Afinal, a lista de arquivos já está gerada, e nós só precisamos exibi-la (com um echo por exemplo):

:~$ echo dir*
dir1 dir2 dir3

9.4 – Expansão de chaves

A expansão de chaves ( )é um mecanismo para gerar strings a partir de padrões.

Exemplos:

:~$ echo a{3,5,7}
a3 a5 a7

:~$ echo a{0..9}
a1 a2 a3 a4 a5 a6 a7 a8 a9

:~$ echo b{a..z}nana
banana bbnana bcnana ... bxnana bynana bznana

:~$ touch teste-{01,02,03}.txt
:~$ ls
teste-01.txt teste-02.txt teste-03.txt

Também podemos definir "saltos" nas sequências geradas:

:~$ echo {0..9..2}
0 2 4 6 8

Importante! A expansão de chaves acontece antes da expansão de parâmetros, por isso não podemos utilizá-las dentro das chaves…

:~$ inicio=2
:~$ echo {$inicio..20}
{2..20}    # A expansão é inválida como expansão de chaves...

9.5 – Quebra (split) de palavras

Depois de processar uma expansão de parâmetro, uma substituição de comando e/ou uma expansão aritmética que não tenha ocorrido entre aspas, o shell utilizará o caractere definido na variável especial IFS (internal field separator) como separador para quebrar a saída em campos (palavras).

Se a variável IFS não tiver sido redefinida, por padrão, sequências dos caracteres
espaço, tabulação e nova linha no começo ou no fim da string, serão
ignoradas e qualquer ocorrência deles no interior da string será utilizada como
delimitador de campos. Se o valor de IFS for nulo, não haverá quebra de palavras.

Veja o exemplo:

alunos=(João Maria "Luis Carlos")
for aluno in ${alunos[*]}; do
    echo $aluno
done

Aqui, o comando composto for irá percorrer todos os elementos do vetor indexado alunos, armazenando temporariamente cada um dos nomes em aluno que, por sua vez, será exibido com o comando echo.

O resultado seria…

João
Maria
Luis
Carlos

Mas “Luis Carlos” deveria aparecer numa única linha, e isso não ocorreu por conta de dois problemas:

  • A expansão da variável ”alunos” foi feita sem aspas.
  • A expansão foi feita usando o caractere * no índice da array.

Observe este outro exemplo:

alunos=(João Maria "Luis Carlos")
for aluno in "${alunos[@]}"; do
    echo $aluno
done

Aqui nós utilizamos o caractere @ no índice e envolvemos a array com aspas, fazendo com que o resultado fosse o esperado:

João
Maria
Luis Carlos

Apenas para você entender a diferença, com as aspas e usando o asterisco no índice da array…

alunos=(João Maria "Luis Carlos")
for aluno in "${alunos[*]}"; do
    echo $aluno
done

A saída seria:

João Maria Luis Carlos

Portanto, a solução mais simples e correta neste caso é usar aspas e o caractere ”@”, mas também seria possível chegar ao mesmo resultado do código original alterando o caractere delimitador de campos na variável IFS:

IFS=$'\n'
alunos=(João Maria "Luis Carlos")
for aluno in ${alunos[*]}; do
    echo $aluno
done

E a saída seria:

João
Maria
Luis Carlos

Alterar o valor do IFS é um procedimento comum, mas deve ser feito com muito critério. Aqui, no nosso curso básico, a minha intenção é apenas demonstrar a expansão de quebra de palavras e mostrar que a variável IFS existe, razão pela qual nós não nos aprofundaremos no assunto por enquanto.

9.6 – Substituição de comandos

Essa expansão já pode ser considerada uma velha conhecida e, portanto,
não há muito mais o que falar sobre ela. Então, nós vamos nos limitar a alguns detalhes
que ainda não mencionamos.

Novas e antigas sintaxes das substituições de comandos

Antiga sintaxe (ainda funciona, mas é considerada obsoleta):

`comando`

Nova sintaxe (preferível):

$( comando )
  • Com a antiga sintaxe, a barra invertida (\) mantém o seu significado literal, a não ser que venha seguida dos caracteres $, acento grave, ou \.
  • Na nova sintaxe, todos os caracteres dentro dos parêntesis compõem o comando e nada é tratado de forma especial.

Substituições de comandos podem ser aninhadas

Antiga sintaxe:

comando \outro comando``

Nova sintaxe:

$( comando $(outro comando) )

Variáveis compartilhadas por sessões diferentes

Apesar das substituições de comandos serem executadas em suas próprias sessões do shell (em subshells), elas recebem cópias das variáveis do ambiente de execução da sessão da qual elas derivam…

:~$ fruta=banana
:~$ saida=$(echo Macacos comem $fruta)
:~$ echo $saida
Macacos comem banana

9.7 – Remoção de aspas

Depois do processamento de qualquer expansão do shell, todas as ocorrências dos caracteres sem aspas \‘, ', e " que não resultarem da expansão serão removidos.

Exemplo:

:~$ fruta=banana
:~$ echo "$fruta"
fruta
:~$ texto="Minha casa é 'velha', mas nem tanto."
:~$ echo "$texto"
Minha casa é 'velha', mas nem tanto.

Aula 8 – Operações Aritméticas | Índice | Aula 10 – Expansões de Parâmetros

Deixe um comentário

O seu endereço de e-mail não será publicado. Campos obrigatórios são marcados com *

Post comment