Skip to content

Introdução

SHAMAN edited this page May 29, 2018 · 119 revisions

O propósito do projeto bashsrc é manter o estilo de programação funcional do bash adicionando uma implementação genérica de tipos e métodos em paralelo com a programação pipe line padrão.

As bibliotecas disponíveis no projeto foram desenvolvidas em shell script utilizando apenas recursos builtin e coreutils. Cada biblioteca é composta por variáveis, tipos e funções que fornecem uma interface para manipulação de texto, regex, leitura e gravação de arquivos, informações do sistema entre outras.

O projeto foi desenvolvido com o objetivo de ser escalável, isto é, permite o usuário criar suas próprias bibliotecas com funções, métodos e tipos de forma simples e eficiente.

O texto a seguir é um guia rápido e introdutório de como utilizar esses recursos e explorar suas funcionalidades.

Importando biblioteca

Para utilizar os recursos de uma biblioteca é necessário importá-la por meio do comando source ou . seguido pelo nome.

Exemplo:

#!/bin/bash

source biblioteca.sh

ou

#!/bin/bash

. biblioteca.sh

A importação carrega na memória as funções, tipos e variáveis declaradas, disponibilizando-as em todo o projeto onde foram importadas.

builtin.sh

A biblioteca builtin é composta por funções básicas para declaração de tipos, iteração de elementos, loops e etc. Todavia é de suma importância e imprescindível para o funcionamento do eco sistema do bashsrc e cuja importação deve preceder qualquer outra biblioteca.

Ao contrário das demais bibliotecas, suas funções não possuem um prefixo, sendo referenciadas apenas por seu identificador curto.

Protótipo:

funcao

Obs: somente na consulta da documentação o prefixo builtin.funcao é requerido.

Exemplo:

Utilizando uma função builtin para converter um número inteiro para binário (base 2).

#!/bin/bash

# Importando
source builtin.sh

# função builtin
bin 255

Saída:

11111111

Funções

A biblioteca contém um conjunto de funções que realizam tarefas especificas onde a nomenclatura de cada função é prefixada pela 'biblioteca' a qual pertence (exceto builtin).

O protótipo de declaração determina a ordem e o tipo de cada argumento. Todos argumentos que compõe a função são obrigatórios e suporta um tipo especifico de dado, gerando uma mensagem de erro caso seja omitido ou inválido.

Protótipo:

funcao <[tipo1]arg1> <[tipo2]arg2> ... => [tipo]
  |        |     |                  |       |
  |        |     |                  |       |___ Tipo do dado de retorno da função.
  |        |     |                  |
  |        |     |                  |__ argumentos variáticos (aceita um ou mais argumentos).
  |        |     |
  |        |     |__ Nome do argumento posicional.
  |        |
  |        |__ Tipo do dado suportado pelo argumento (Flag type ou object_t).
  |
  |__ Identificador válido da função.

object_t é um tipo de objeto que pode ser implementado.

Flag type

O Flag type é um dado mapeado a partir de um expressão de comprimento variável cujo tipo é determinado pela aplicação de um padrão (regex).

A flag indica o tipo de dado suportado pelo argumento cujo valor precisa atender aos critérios de validação.

Flag Critérios
uint Inteiro sem sinal.
int Inteiro com sinal.
float Número de precisão com sinal separado por '.' (ponto) ou ',' (vírgula).
zone Fuso horário.
char Caractere único.
str Uma cadeia de caracteres.
bool Booleano (true ou false).
var Identificador de uma variável ou vetor válido.
array Array indexado. (inicializado)
map Array associativo. (inicializado)
funcname Nomenclatura de função válida.
func Identificador de uma função válida.
srctype Identificador de objeto de implementação terminado em _T ou _t.
st_member Identificador de membro da estrutura.
bin Número binário (base 2).
hex Número hexadecimal (base 16).
oct Número octal (base 8).
size Unidade de armazenamento. (12KB, 1MB, 10G, 2TB ...)
12h Hora no formato 12 horas. (HH:MM -> 1..12)
24h Hora no formato 24 horas. (HH:MM -> 0..23)
date Data no formato. (DD/MM/YYYY)
hour Hora. (0..23)
min Minutos. (0..59)
sec Segundos. (0..59)
mday Dia do mês. (1..31)
mon Dia da semana. (1..12)
year Ano. inteiro positivo com 4 ou mais dígitos.
yday Dias do ano. (1..366)
wday Dias da semana. (1..7)
url Endereço web. (http|https|ftp|smtp)://www?...
email Endereço de email.
ipv4 protocolo ipv4 (32 bits)
ipv6 protocolo ipv6 (128 bits)
mac Endereço MAC Address (xx:xx:xx:xx:xx:xx)
slice Intervalo numérico. [int:int]
uslice Intervalo numérico positivo [uint:uint]
keyword Palavra chave que indica que 'type' tem que ser igual a 'name'. (somente getopt.parse)
dir Diretório válido.
file Arquivo padrão.
path Caminho válido.
flag Sequência de caracteres [a-zA-Z_].

Além da Flag type as funções também suportam tipos de objetos implementados que contém o sufixo _t ou _T em sua nomenclatura.

Exemplo

Protótipo da função os.open que recebe como argumento um objeto do tipo file_t

func os.open <[file_t]var> <[str]filename> <[uint]flag> => [bool]

Obs: a palavra-chave func informa que o protótipo do objeto é uma função. (somente para documentação)

Outro exemplo é o protótipo da função time.gmtime que recebe uma estrutura que é implementada pelo tipo time_t.

func time.gmtime <[time_t]struct> <[uint]seconds>

Funções com retorno [bool]

Diferentemente dos demais tipos o bool não retorna explicitamente um valor, mas define o código de status da função após a execução; Sendo 0 (verdadeiro) ou != 0 (falso) e que é acessada através da variável $?.

Exemplo:

Utilizando a função str.compare para comparar duas strings e que retorna '0' se forem iguais ou '1' para diferentes.

# Comparando as strings.
str.compare "shell script" "SHELL SCRIPT"
echo $?

Saída:

1

Também é possível verificar o status da função executando-a diretamente em um bloco condicional if.

Exemplo:

if str.compare "shell" "shell"; then
    echo "Iguais"
else
    echo "Diferentes"
fi

ou

str.compare "shell" "shell" && echo "Iguais" || echo "Diferentes"

Saída:

Iguais

Argumentos posicionais:

Cada função possui um identificador exclusivo composto pelo sufixo da biblioteca a qual pertence (se disponível) e que deve ser chamada com os argumentos posicionais dos tipos pré-estabelecidos por seu protótipo de declaração.

A ordem dos argumentos posicionais é obrigatória assim como o total de argumentos suportados pela função.

Protótipo:

                          Total de argumentos: 4
                     _______________|_________________
                    |                                 |
    Função         $1         $2         $3          $4  ->  Argumentos posicionais
      |             |          |          |           |           
string.replace <[str]exp> <[str]old> <[str]new> <[int]count> => [str]
                                                                  |
                                                            Tipo do retorno

É recomendável a utilização das aspas duplas " ou simples ' na passagem dos argumentos para evitar que informações vazem para os demais argumentos posicionais.

Exemplo:

Utilizando a função acima para realizar a substituição de uma string por outra em uma expressão.

#!/bin/bash

source string.sh

string.replace 'Programar em [linguagem] é vida.' 'linguagem' 'shell script' 1

Saída:

Programar em [shell script] é vida.

Obs: use aspas duplas " caso precise expandir o valor de uma variável.

Salvando retorno:

Para capturar o retorno de uma função é necessário chamá-la em um sub-shell utilizando o conjunto de expansão $(...).

var=$(funcao arg1 arg2 ...)

Exemplo:

#!/bin/bash

source string.sh

# Texto
texto='Seja livre, use Linux'

# Salvando retorno.
reverso=$(string.reverse "$texto")

# Imprimindo
echo "$reverso"

Saída:

xuniL esu ,ervil ajeS

Empilhamento:

O empilhamento é um conjunto de funções cujo o valor de retorno é tratado pela função externa subsequente.

Protótipo:

funcao1 "$(funcao2 "$(funcao 3)")"

Exemplo:

#!/bin/bash

source string.sh

# Texto
texto='Seja livre, use <so>'

# Converte o texto para maiúsculo antes de realizar a substituição.
string.replace "$(string.toupper "$texto")" "<SO>" "LINUX" 1

Saída:

SEJA LIVRE, USE LINUX

Obs: a prioridade de expansão acontece de dentro para fora, ou seja, ocorre do sub-shell mais interno para o externo subsequente.

Função como argumento:

Uma função que recebe como argumento outra função que é executada a cada iteração e que recebe como argumento posicional $1 o elemento atual, anexando o valor de retorno da função de iteração.

Veja o protótipo da função fnmap da biblioteca builtin.sh.

                                          (opcional)
                                              |
                     (função de iteração)[argumentos]
                              |               |
func fnmap <[var]name> <[func]funcname> <[str]args> ...
                |             
            (variável)

Obs: args é um argumento variático, ou seja, pode ser especificado um ou mais argumentos dependendo da função de iteração aplicada.

A função fnmap lê os caracteres armazenados em name e cada iteração chama funcname passando como argumento o caractere atual.

Exemplo:

#!/bin/bash

source builtin.sh

# variável
distro='SLACKWARE'

# função de iteração.
colunas(){
    # Retorna para 'fnmap' o caractere modificado.
    echo "[$1]"
}

fnmap distro colunas

Saída:

[S][L][A][C][K][W][A][R][E]

Também é possível passar argumentos para a função de iteração. Veja o exemplo abaixo utilizando a função string.repeat para triplicar os caracteres contidos na expressão.

Exemplo:

#!/bin/bash

source string.sh

distro='SLACKWARE'

fnmap distro string.repeat 3

Saída:

SSSLLLAAACCCKKKWWWAAARRREEE

Flag types (var, array, map, func e object_t)

Os argumentos com a flag type var, array, map, func ou object_t são ponteiros para objetos existentes associados ao seu identificador (nome) para acesso direto e que deve ser especificado sem o caractere de expansão $ (cifrão).

Exemplo:

Considere o protótipo da função 'swap' que troca os valores entre variáveis e que recebe dois argumentos do tipo var.

Protótipo:

func swap <[var]name1> <[var]name2>

Código:

# Variáveis
var1=10
var2=20

# Passando argumentos
// * INCORRETO * //
swap $var1 $var2

// * CORRETO * //
swap var1 var2

Map

Um map é um array associativo que possui uma estrutura de dados composta por um conjunto de elementos referenciados por uma chave ou valor. As chaves podem ser definas pelo usuário e armazenadas na estrutura.

Para declarar um array associativo utilize os comandos local ou declare com parâmetro -A seguido pelo identificador da variável.

Exemplo:

local -A var=()
declare -A var=()

Consulte a documentação para mais detalhes: help declare ou help local.

Array

Array é uma estrutura de dados que armazena uma coleção de elementos que são referenciados por um índice, conhecida como array indexado.

Para declarar um array indexado utilize os comandos local ou declare com o parâmetro -a seguido pelo identificador da variável.

Exemplo:

local -a var=()
declare -a var=()

Uma variável também pode ser considerada como um array indexado podendo ser referenciada diretamente sem uma declaração explicita.

Exemplo:

var=(item1 item2 ...)
var[10]='item10'

Inicializando (array/map)

Funções com argumentos do tipo array ou map precisam ser previamente instanciadas antes passá-las na função.

Exemplo:

Considere o protótipo da função map.list que lista as chaves e valores do map especificado em name.

func map.list <[map]name> => [key|object]

Código:

/* INCORRETO */
# Não é um tipo 'map'
meu_map=''

map.list meu_map

---

/* CORRETO */
# Map
declare -A meu_map=()

map.list meu_map

Implementação de tipos (var)

Shell script não possui orientação a objetos, métodos ou heranças. Porém, como qualquer outra linguagem existe o escopo de visibilidade durante a declaração de uma variável e com a abstração adequada é possível a criação de funções que simulam métodos de acesso por entidade.

A função var é responsável por inicializar e implementar os métodos do objeto. Uma variável só pode ser implementada por um único objeto. (veja também: del)

Protótipo:

var varname ... object_t

varname nome da variável a ser implementada. 'object_' nome do objeto de implementação.

Todo o objeto implementado é global, ou seja, seus métodos são visíveis por todo o código, exceto o valor da variável da entidade que só pode ser acessada dentro do seu escopo de declaração. (exceto struct_t)

Exemplo:

#!/bin/bash

source builtin.sh
source string.sh

# Implementa os objetos.
var var_g string_t
var var_l string_t

var_p='Linux'

funcao(){
    # declara 'var_l' como local
    local var_l
    var_l='Windows'
}

# Chama 'funcao' para atribuir o valor de 'val_l'.
funcao

# Executa o método 'toupper' dos objetos implementados.
echo "var_g = $(var_g.toupper)"
echo "val_l = $(var_l.toupper)"

Saída:

var_p = LINUX
val_l = 

Note que apesar do método val_l.toupper ter sido executado com sucesso, nenhum valor foi retornado.

Método/Argumento posicional

Os métodos do objeto recebem o valor ou o identificador da variável implementada como argumento posicional $1 em sua chamada, dependendo do tipo da função pode ser por valor ou referência. De qualquer modo o método deve ser chamado omitindo o seu primeiro argumento.

Exemplo 1:

Veja o protótipo da função string.len que calcula o comprimento de uma string.

func string.len <[str]exp> => [uint]
                     |
                     $1

Usando a função:

#!/bin/bash

source string.sh

# Usando a função
string.len "shell script"

Saída:

12

Usando o método:

#!/bin/bash

source builtin.sh
source string.sh

# Implementa texto com o tipo 'string_t'.
var texto string_t

# Armazena o texto
texto='shell script'

# Chama o método
texto.len

Saída:

12

Exemplo 2:

Utilizando a função string.repeat para repetir 'N' vezes uma determina string.

Protótipo:

func string.repeat <[str]exp> <[uint]count> => [str]
                       |
                       $1

Usando a função:

#!/bin/bash

source builtin.sh
source string.sh

# Chama a função
texto.repeat 'LINUX-' 5

Saída:

LINUX-LINUX-LINUX-LINUX-LINUX-

Usando o método:

#!/bin/bash

source builtin.sh
source string.sh

# Implementa 'texto'.
var texto string_t

# Texto
texto='LINUX-'

# Chama o método
texto.repeat 5

Saída:

LINUX-LINUX-LINUX-LINUX-LINUX-

Clone this wiki locally