O Julio Neves, uma das referências nacionais sobre shell script, autor de obras sobre o assunto e instrutor frequente em cursos sobre Bash e Zenity, enviou o artigo abaixo sobre algumas das novidades trazidas na versão 4 do Bash, que publico na íntegra com os agradecimentos ao mestre!

Algumas novidades do Bash 4.0

Por Julio Neves

1 – Novas substituições de parâmetros

1.1 - ${parâmetro:n}

Equivale a um
cut

com a opção
-c,

porém muito mais rápido. Preste a atenção, pois neste caso, a origem da contagem é zero.

$ TimeBom=Flamengo

$ echo ${TimeBom:3}

mengo

Essa Expansão de Parâmetros que acabamos de ver, também pode extrair uma sub cadeia, do fim para o principio, desde que seu segundo argumento seja negativo.

$ echo ${TimeBom: -5}

mengo

$ echo ${TimeBom:-5}

Flamengo

$ echo ${TimeBom:(-5)}

mengo

1.2 – ${!parâmetro}

Isto equivale a uma indireção, ou seja devolve o valor apontado por uma variável cujo nome está armazenada em parâmetro.

Exemplo:

$ Ponteiro=VariavelApontada

$ VariavelApontada=”Valor Indireto”

$ echo “A variável \$Ponteiro aponta para \”$Ponteiro\”

> que indiretamente aponta para \”${!Ponteiro}\”"

A variável $Ponteiro aponta para “VariavelApontada”

que indiretamente aponta para “Valor Indireto”

1.3 – ${!parâmetro@} ou ${!parâmetro*}

Ambas expandem para os nomes das variáveis prefixadas por parâmetro. Não notei nenhuma diferença no uso das duas sintaxes.

Exemplos:

Vamos listar as variáveis do sistema começadas com a cadeia
GNOME:

$ echo ${!GNOME@}

GNOME_DESKTOP_SESSION_ID GNOME_KEYRING_PID GNOME_KEYRING_SOCKET

$ echo ${!GNOME*}

GNOME_DESKTOP_SESSION_ID GNOME_KEYRING_PID GNOME_KEYRING_SOCKET

1.4 – ${parâmetro^} e ${parâmetro,}

Essas expansões foram introduzidas a partir do Bash 4.0 e modificam a caixa das letras do texto que está sendo expandido. Quando usamos circunflexo
(^),

a expansão é feita para maiúsculas e quando usamos vírgula
(,),

a expansão é feita para minúsculas.

Exemplo:

$ Nome=”botelho”

$ echo ${Nome^}

Botelho

$ echo ${Nome^^}

BOTELHO

$ Nome=”botelho carvalho”

$ echo ${Nome^}

Botelho carvalho # Que pena…

Um fragmento de script que pode facilitar a sua vida:

read -p “Deseja continuar (s/n)? “

[[ ${REPLY^} == N ]] && exit

Esta forma evita testarmos se a resposta dada foi um
N

(maiúsculo) ou um
n

(minúsculo).

No Windows, além dos vírus e da instabilidade, também são frequentes nomes de arquivos com espaços em branco e quase todos em maiúsculas. No próximo exemplo  veremos como passá-los para minúsculas:

$ cat trocacase.sh

#!/bin/bash

# Se o nome do arquivo tiver pelo menos uma

#+ letra maiúscula, troca-a para minúscula

for Arq in *[A-Z]* # Pelo menos 1 minúscula

do

if [ -f "${Arq,,}" ] # Arq em minúsculas já existe?

then

echo ${Arq,,} já existe

else

mv “$Arq” “${Arq,,}”

fi

done

2 – Substituição de chaves

Elas são usadas para gerar cadeias arbitrárias, produzindo todas as combinações possíveis, levando em consideração os prefixos e sufixos.

Existiam 5 sintaxes distintas, porém o Bash 4.0 incorporou uma 6ª. Elas são escritas da seguinte forma:

  1. {lista},

    onde
    lista

    são cadeias separadas por vírgulas;

  2. {inicio..fim};
  3. prefixo{****},

    onde os asteriscos
    (****)

    podem ser substituídos por
    lista

    ou por um par
    inicio..fim;

  4. {****}sufixo,

    onde os asteriscos
    (****)

    podem ser substituídos por
    lista

    ou por um par
    inicio..fim;

  5. prefixo{****}sufixo, onde os asteriscos (****) podem ser substituídos por lista ou por um par inicio..fim;
  6. {inicio..fim..incr},

    onde
    incr

    é o incremento (ou razão, ou passo). Esta foi introduzida a partir do Bash 4.0.

$ echo {1..A} # Letra e número não funfa

{1..A}

$ echo {0..15..3} # Incremento de 3, só no Bash 4

0 3 6 9 12 15

$ echo {G..A..2} # Incremento de 2 decresc, só no Bash 4

G E C A

$ echo {000..100..10} # Zeros à esquerda, só no Bash 4

000 010 020 030 040 050 060 070 080 090 100

$ eval \>{a..c}.{ok,err}\;

$ ls ?.*

a.err a.ok b.err b.ok c.err c.ok

A sintaxe deste último exemplo pode parecer rebuscada, mas substitua o
eval

por
echo

e verá que aparece:

$ echo \>{a..c}.{ok,err}\;

>a.ok; >a.err; >b.ok; >b.err; >c.ok; >c.err;

Ou seja o comando para o Bash criar os 6 arquivos. A função do
eval

é executar este comando que foi montado.

O mesmo pode ser feito da seguinte maneira:

$ touch {a..z}.{ok,err}

Mas no primeiro caso, usamos Bash puro, o que torna esta forma pelo menos 100 vezes mais rápida que a segunda que usa um comando externo
(touch).