-
Notifications
You must be signed in to change notification settings - Fork 7
Introdução
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 builtindo interpretador de comandos bash ecoreutils. Cada biblioteca é composta por variáveis, tipos e funções que fornecem uma interface para manipulação de texto, regex, informações do sistema entre outras.
O projeto foi desenvolvido com o objetivo de ser escalável, ou seja, permitindo que o usuário crie 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.
Para utilizar os recursos de uma biblioteca é necessário importá-la em seu script ou projeto por meio do comando source ou . seguido pelo nome.
Exemplo:
#!/bin/bash
source biblioteca.shou
#!/bin/bash
. biblioteca.shA importação carrega na memória as funções, tipos e variáveis declaradas, disponibilizando-as em todo o projeto onde foram importadas.
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 255Saída:
11111111
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 <arg1[tipo1]> <arg2[tipo2]> ... -> [tipo]
| | | | |
| | | | |___ Tipo do dado de retorno da função.
| | | |
| | | |__ argumentos variáticos (aceita um ou mais argumentos).
| | |
| | |__ Tipo do dado suporado pelo argumento. (tipo básico ou objeto)
| |
| |__ Nome do argumento.
|
|__ Identificador da função.
```
> `objeto` é um tipo de dado definido pelo usuário.
### Tipos básicos
O ecossitema do **bashsrc** suporta um conjunto de dados que são verificados na passagem de argumentos em funções ou estruturas cuja validação é realizada por ERE (expressão regular estentida) a nível de execução. São eles:
|Tipo|Descrição|
|-|-|
|uint|Inteiro sem sinal.|
|int|Inteiro com sinal.|
|float|Número de precisão com sinal separado por '.' (ponto).|
|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)|
|function|Nomenclatura de função válida.|
### Objetos
Além dos tipos básicos é possível definir tipos personalizados que podem implementar métodos ou estruturas. Por convenção é utilizado sufixos `_t` ou `_st` em nomenclaturas afim de especificar o tipo do dado.
|Nomenclatura|Descrição|
|-|-|
|var\_t|Tipo que implementa um ou mais métodos|
|var\_st|Tipo que implementa uma estrutura|
**Exemplo**
O objeto `string_t` é um tipo que implementa todos os métodos que fazem referência as funções presentes na bibliioteca `string.sh`, fornecendo diferentes interfaces de programação.
Considere ambos os códigos abaixo que produzem o mesmo resultado.
```bash
#!/bin/bash
source string.sh
# Função
string.upper 'shell script'
```
ou
```bash
#!/bin/bash
source string.sh
# Implementação.
var texto string_t
# Atribui valor
texto='shell script'
# Método
texto.upper
```
**Saída:**
```bash
SHELL SCRIPT
```
**Funções (retorno)**
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, são eles:
|Código|Descrição|
|-|-|
|0|Sucesso|
|!= 0|Erro|
**Exemplo:**
Utilizando a função `str.compare` para comparar duas strings e que retorna '0' se forem iguais ou '1' para diferentes.
```bash
# 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:**
```bash
if str.compare "shell" "shell"; then
echo "Iguais"
else
echo "Diferentes"
fi
```
ou
```bash
str.compare "shell" "shell" && echo "Iguais" || echo "Diferentes"
```
**Saída:**
```
Iguais
```
**Função variádica:**
É uma função que suporta um número indeterminado de argumentos a direita cuja declaração termina com `...`. Veja o protótipo abaixo:
```
function string.field <expr[str]> <sep[str]> <field[int]> ... [str]|[bool]
```
A função requer no mínimo 3 argumentos, sendo o último a direita variádico, ou seja, podendo ser especificado mais de um valor.
Chamadas válidas:
```bash
string.field 'f1,f2,f3,f4,f5' ',' 1
string.field 'f1,f2,f3,f4,f5' ',' 1 3 5
string.field 'f1,f2,f3,f4,f5' ',' {3..5} # glob
```
**Salvando retorno:**
Para capturar o retorno de uma função é necessário chamá-la em um sub-shell utilizando o conjunto de expansão `$(...)`.
```bash
var=$(funcao arg1 arg2 ...)
```
**Exemplo:**
```bash
#!/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:**
```bash
#!/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.upper "$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]
| |
function fnmap <iterable[array]> <funcname[function]> <[str]args> ...
|
(variável)
```
A função `fnmap` lê o array e cada iteração chama `funcname` passando como argumento o elemento atual.
**Exemplo:**
```bash
#!/bin/bash
source string.sh
# Função
colunas()
{
# Retorna o caractere entre '[...]'
echo "[$1]"
}
string.fncmap 'SLACKWARE' colunas
string.fncmap 'SLACKWARE' string.repeat 3 # Passando argumentos.
```
**Saída:**
```
[S][L][A][C][K][W][A][R][E]
SSSLLLAAACCCKKKWWWAAARRREEE
```
### 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:**
```bash
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:**
```bash
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:**
```bash
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`.
```
function map.list <[map]name> => [key|object]
```
**Código:**
```bash
/* 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:**
```bash
#!/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.upper)"
echo "val_l = $(var_l.upper)"
```
**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 <exp[str]> => [uint]|[bool]
|
$1
```
**Usando a função:**
```bash
#!/bin/bash
source string.sh
# Usando a função
string.len "shell script"
```
**Saída:**
```
12
```
**Usando o método:**
```bash
#!/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:**
```
function string.repeat <exp[str]> <count[uint]> -> [str]
|
$1
```
**Usando a função:**
```bash
#!/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:**
```bash
#!/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-
```
### Estruturas
A implementação dos dados é feita de forma genérica por meio de métodos instanciados com nomenclaturas e tipos previamente definidos e referenciados em um `map` do objeto implementado para leitura e escrita.
**Protótipo:**
```
estrutura.__add__ membro1 tipo \
membro2 tipo \
membro3 tipo
ou
estrutura.__add__ membro1 tipo membro2 tipo membro3 tipo
```
> `tipo` pode ser uma `tipo básico` ou `objeto` válido.
O objeto implementado por `struct_t` é **global**, ou seja, é visível em todo o código e pode ser acessado por seu identificador.
**Exemplo:**
```
/* CORRETO */
var nome_t struct_t
var nome_T struct_t
var _nome_t struct_t
var __nome1_nome2_T struct_t
/* ERRO */
var nome struct_t
var nome_ struct_t
```
> Obs: É retornada uma mensagem de erro se o objeto implementado por `struct_t` for um tipo já existente.
Após a declaração ele se torna um **objeto_t** que deve ser implementado para atribuição do valor dos membros da estrutura.
**Exemplo:**
```bash
#!/bin/bash
source builtin.sh
source struct.sh
# Implementando o tipo 'struct_t'
var objeto_t struct_t
# adicionando os membros da estrutura.
objeto_t.__add__ membro1 uint \
membro2 uint \
membro3 uint
# Implementando 'st' com 'objeto_t'
var st objeto_t
# Atribuindo valores
st.membro1 = 1
st.membro2 = 2
st.membro3 = 3
```
**Leitura e gravação**
O acesso ao membro da estrutura deve ser feito por `referência` ou `atribuição`.
|Por|Descrição|
|-|-|
|Referência|Chamada direta ao membro da estrutura para leitura do dado armazenado.|
|Atribuição|Atribui o valor a um membro especifico da estrutura e que deve ser precedido pelo operador '='.|
> Obs: deve conter um espaço inicial e final entre o operador de atribuição '='.
**Protótipos:**
```
estrutura.membro # Referência.
estrutura.membro = "valor" # Atribuição.
```
**Composição**
A **composição de estruturas** é quando um membro é instanciado como um tipo `struct_t`, herdando os membros da estrutura especificada.
Para realizar uma **composição** é necessário especificar o nome da estrutura que irá compor na passagem do tipo.
**Protótipo:**
```
struct.__add__ estrutura1 \
membro1 estrutura2\
membro2 estrutura3
```
**Estrutura**
```
estrutura1.membro1.estrutura2_membro
estrutura1.membro2.estrutura3_membro
```
**Exemplo:**
```bash
#!/bin/bash
source builtin.sh
source struct.sh
# Implementa as estruturas
var cliente_st local_st info_st struct_t
# info_st
info_st.__add__ sexo str \
cor str \
civil str
# local_st
local_st.__add__ endereco str \
cidade str \
cep uint
# client_t
# Compõe as estruturas local_st e info_st.
cliente_st.__add__ nome str \
sobrenome str \
idade uint \
local local_st \
info info_st
# Implementa 'cliente' com o tipo 'client_st'
var cliente cliente_st
# Atribuindo valores
cliente.nome = 'Vanessa'
cliente.sobrenome = 'Oliveira'
cliente.idade = '42'
cliente.info.sexo = 'Feminino'
cliente.info.cor = 'Parda'
cliente.info.civil = 'Solteira'
cliente.local.endereco = 'Rua imaginária N 000 Apt -1'
cliente.local.cidade = 'Aiuruoca'
cliente.local.cep = '11111111'
```
- E-mail: shellscriptx@gmail.com
- Juliano Santos (SHAMAN)
