-
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 builtin
do 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.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.
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
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.
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. |
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.
#!/bin/bash
source string.sh
# Função
string.upper 'shell script'
ou
#!/bin/bash
source string.sh
# Implementação.
var texto string_t
# Atribui valor
texto='shell script'
# Método
texto.upper
Saída:
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.
# 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
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:
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 $(...)
.
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.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:
#!/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
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
ouhelp local
.
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
.
function 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
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
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
)
Declarações:
/* CORRETO */
var v1 objeto
var v1 v2 v3 objeto
var {a..b} objeto
/* INCORRETO */
var 1v objeto
var 10 objeto
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.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:
#!/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:
function string.repeat <exp[str]> <count[uint]> -> [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-
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 umatipo básico
ouobjeto
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:
#!/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:
#!/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'