├── LICENSE
├── README.md
├── bashsrc.png
├── bin
└── bashsrc
└── src
├── array.sh
├── builtin.sh
├── cpu.sh
├── error.sh
├── getopt.sh
├── grp.sh
├── http.sh
├── json.sh
├── log.sh
├── map.sh
├── mem.sh
├── net.sh
├── os.sh
├── path.sh
├── ps.sh
├── rand.sh
├── regex.sh
├── setup.sh
├── ssh.sh
├── string.sh
├── struct.sh
├── textutil.fonts
├── textutil.sh
├── time.sh
└── user.sh
/README.md:
--------------------------------------------------------------------------------
1 | ## bashsrc 2.0.0
2 |
3 | 
4 |
5 | ### Sobre
6 |
7 | O **bashsrc** é um projeto _open source_ distribuído em uma coleção de bibliotecas desenvolvidas em **shell script**, com um conjunto de funções úteis que fornece ao desenvolvedor um estilo de programação funcional com implementação de "tipos".
8 |
9 | O foco principal é a compatibilidade com o interpretador de comandos **BASH 4.3.0 (ou superior)**, cuja funções são desenvolvidas utilizando apenas recursos `built-in` e `coreutils`, evitando a utilização de dependências de pacotes externos que geram ‘coprocs’ durante a execução. Porém alguns critérios serão levados em consideração para tal aplicação: _desempenho, viabilidade, compatibilidade, distribuição da dependência_ entre outros, ficando de responsabilidade do desenvolvedor verificar e reportar tais dependências se houverem.
10 |
11 | ### Dependência
12 |
13 | |Pacote|Versão|Descrição|
14 | |-|-|-|
15 | |bash|4.3 (ou superior)|Interpretador de comandos BASH (Bourne-Again Shell).|
16 |
17 | ### Documentação
18 |
19 | A documentação padrão está disponível no arquivo fonte de cada biblioteca e que pode ser acessada pela utilitário [bashsrc](https://github.com/shellscriptx/bashsrc/wiki/Utilit%C3%A1rio) via linha de comando e distribuída junto ao projeto.
20 |
21 |
22 | **Para mais informações:** [clique aqui](https://github.com/shellscriptx/bashsrc/wiki)
23 |
24 | ### Reportando falhas
25 |
26 | * E-mail: shellscriptx@gmail.com
27 |
28 | ### Desenvolvedor
29 |
30 | * Juliano Santos [(SHAMAN)](https://t.me/x_SHAMAN_x)
31 |
32 | ### Comunidades
33 |
34 | * [Telegram (grupo)](https://t.me/shellscript_x)
35 |
36 | * [Facebook (fanpage)](https://fb.com/shellscriptx)
37 |
38 | * [Facebook (grupo)](https://fb.com/groups/shellscriptx)
39 |
40 | * [Blog](https://www.shellscriptx.blogspot.com.br)
41 |
42 | ### Gostaria de contribuir com o projeto? [clique aqui](https://www.padrim.com.br/apoiar?projeto_id=4707)
43 |
44 | 
45 |
--------------------------------------------------------------------------------
/bashsrc.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/shellscriptx/bashsrc/d3e80e590830fe6ae9c21570447313cf66d48f1e/bashsrc.png
--------------------------------------------------------------------------------
/bin/bashsrc:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 |
3 | # Copyright 2018 Juliano Santos [SHAMAN]
4 | #
5 | # This file is part of bashsrc.
6 | #
7 | # bashsrc is free software: you can redistribute it and/or modify
8 | # it under the terms of the GNU General Public License as published by
9 | # the Free Software Foundation, either version 3 of the License, or
10 | # (at your option) any later version.
11 | #
12 | # bashsrc is distributed in the hope that it will be useful,
13 | # but WITHOUT ANY WARRANTY; without even the implied warranty of
14 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 | # GNU General Public License for more details.
16 | #
17 | # You should have received a copy of the GNU General Public License
18 | # along with bashsrc. If not, see .
19 | #
20 |
21 | readonly BASENAME=${0##*/}
22 | readonly BASHSRC_VERSION=2.0.0
23 |
24 | if [ ! -v BASHSRC_PATH ]; then
25 | echo "$BASENAME: erro: 'BASHSRC_PATH' variável de ambiente não configurada." 1>&2
26 | exit 1
27 | fi
28 |
29 | # Ativa globbing
30 | shopt -s extglob
31 | set +f
32 |
33 | # Flags de informação.
34 | readonly -a IFLAGS=(
35 | NAME
36 | SYNOPSIS
37 | DESCRIPTION
38 | VERSION
39 | AUTHORS
40 | BUGS
41 | COPYRIGHT
42 | LINKS
43 | DEPENDS
44 | EMAILS
45 | PLATFORMS
46 | )
47 |
48 | # Flags de ajuda.
49 | readonly -a HFLAGS=(
50 | FUNCTION
51 | TYPE
52 | STRUCT
53 | CONST
54 | MAP
55 | ARRAY
56 | )
57 |
58 | # Regex/Grupos
59 | readonly -A RE=(
60 | [flag]='^\s*#+\s*\.'
61 | [nocomm]='^[^#]*$'
62 | [typedef]='^[^#]*\s*typedef\s+([a-zA-Z_][a-zA-Z0-9_]*)'
63 | [func]="${RE[flag]}(FUNCTION)\s+"
64 | [type]="${RE[flag]}(TYPE|STRUCT|CONST|MAP|ARRAY)\s+"
65 | )
66 |
67 | function usage()
68 | {
69 | cat << _eof
70 | $BASENAME: ferramenta de ambiente e documentação.
71 | Uso: $BASENAME [OPÇÕES]
72 |
73 | Argumentos obrigatórios para opções longas também são para opções curtas.
74 |
75 | -l, --list - Lista os sources disponíveis em '\$BASHSRC_PATH'.
76 | -e, --env - Exibe o ambiente configurado em '\$BASHSRC_PATH'.
77 | -d, --doc [.|] - Exibe a documentação da biblioteca, função ou tipo.
78 | -h, --help - Exibe ajuda e sai.
79 | -c, --check-conflicts - Verifica se há conflito de tipos entre bibliotecas em '\$BASHSRC_PATH'.
80 | -v, --version - Exibe a versão e sai.
81 |
82 | Desenvolvido por: Juliano Santos [SHAMAN]
83 | Reportar falhas:
84 | Wiki:
85 | _eof
86 | }
87 |
88 | function list_sources()
89 | {
90 | local dir file
91 | local srcdir=${1:-$BASHSRC_PATH/src}
92 |
93 | for dir in "${srcdir[@]}"; do
94 | for file in "$dir/"*; do
95 | if [[ -d "$file" ]]; then
96 | list_sources "$file"
97 | else
98 | [[ $file =~ \.sh$ ]] &&
99 | echo "$file"
100 | fi
101 | done
102 | done
103 |
104 | return 0
105 | }
106 |
107 | function view_doc()
108 | {
109 | local srcdir=$BASHSRC_PATH/src
110 | local hflags=${HFLAGS[@]}
111 | local iflags=${IFLAGS[@]}
112 | local srcname=${1##*/}
113 | local srcfile=${1%%.*}.sh
114 | local comp match help
115 |
116 | hflags=${RE[flag]}"(${hflags// /|})\s+(.+)$"
117 | iflags=${RE[flag]}"(${iflags// /|})$"
118 |
119 | if [[ ! $1 ]]; then
120 | printf '%s: doc: requer nome da biblioteca\n' "$BASENAME" 1>&2
121 | return 1
122 | elif [[ ! -e "$srcdir/$srcfile" ]]; then
123 | printf '%s: doc: "%s" biblioteca não encontrada\n' "$BASENAME" "$1" 1>&2
124 | return 1
125 | fi
126 |
127 | # Obtem nomenclatura composta.
128 | IFS='.' read _ comp <<< "$srcname"
129 |
130 | while read -r line; do
131 | if [[ $line =~ ${RE[nocomm]} ]]; then
132 | help=
133 | # Informação
134 | elif [[ ! $comp && $line =~ $iflags ]]; then
135 | match=true
136 | echo "${BASH_REMATCH[1]}"
137 | help=true
138 | continue
139 | # Ajuda
140 | elif [[ ! $comp && $line =~ $hflags ]]; then
141 | match=true
142 | echo "${BASH_REMATCH[1],,} ${BASH_REMATCH[2]}"
143 | continue
144 | # Funções e Tipos
145 | elif [[ $line =~ ${RE[func]}(${srcname#builtin.}.*)$ ]] ||
146 | [[ $line =~ ${RE[type]}(${srcname#*.})$ ]]; then
147 | match=true
148 | help=true
149 | echo "${BASH_REMATCH[1],,} ${BASH_REMATCH[2]}"
150 | continue
151 | fi
152 |
153 | # Exibe detalhes do subitem caso seja especificado.
154 | [[ $help ]] && printf '%4s%s\n' '' "${line#+(#)}"
155 |
156 | # Define o status de retorno.
157 | # Se nehuma referência for encontrada status será igual à 'false'.
158 | ${match:-false}
159 | done < "$srcdir/$srcfile" || {
160 | # status: false
161 | printf "%s: doc: '%s' referência não encontrada\n" "$BASENAME" "$srcname" 1>&2
162 | return 1
163 | }
164 |
165 | return 0
166 | }
167 |
168 | check_conflicts()
169 | {
170 | local srcfile line err
171 | local -A srctypes
172 |
173 | # Lista todas as bibliotecas disponíveis.
174 | while read srcfile; do
175 | while read -r line; do
176 | # Trata a linha enquanto houver tipo definido (typedef)
177 | while [[ $line =~ ${RE[typedef]} ]]; do
178 | # Verifica se o tipo já existe, caso já exista imprime na saída
179 | # padrão as bibliotecas conflitantes.
180 | if [[ ${srctypes[${BASH_REMATCH[1]}]} ]]; then
181 | printf '== Conflito ==\n\nTipo: %s\n\nBiblioteca: %s\nBiblioteca: %s\n\n' \
182 | "${BASH_REMATCH[1]}" \
183 | "${srctypes[${BASH_REMATCH[1]}]}" \
184 | "$srcfile"
185 |
186 | err=1 # status
187 | else
188 | # Anexa o tipo.
189 | srctypes[${BASH_REMATCH[1]}]=$srcfile
190 | fi
191 | line=${line/typedef+( )${BASH_REMATCH[1]}/} # Atualiza linha.
192 | done
193 | done < "$srcfile" # Biblioteca
194 | done < <(list_sources)
195 |
196 | return ${err:-0}
197 | }
198 |
199 | # Parâmetros.
200 | case $1 in
201 | -v|--version) printf '%s-%s\n' "$BASENAME" "$BASHSRC_VERSION";;
202 | -e|--env) printf 'BASHSRC_PATH=%s\nPATH=%s\n' "$BASHSRC_PATH" "$PATH";;
203 | -l|--list) list_sources;;
204 | -d|--doc) view_doc "$2";;
205 | -c|--check-conflicts) check_conflicts;;
206 | -h|--help) usage;;
207 | *) printf "Uso: %s [OPÇÕES]\nTente: '%s --help' para obter mais informações.\n" "$BASENAME" "$BASENAME";;
208 | esac
209 |
210 | exit $?
211 |
212 | # /* BASHSRC */
213 |
--------------------------------------------------------------------------------
/src/array.sh:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 |
3 | # Copyright 2018 Juliano Santos [SHAMAN]
4 | #
5 | # This file is part of bashsrc.
6 | #
7 | # bashsrc is free software: you can redistribute it and/or modify
8 | # it under the terms of the GNU General Public License as published by
9 | # the Free Software Foundation, either version 3 of the License, or
10 | # (at your option) any later version.
11 | #
12 | # bashsrc is distributed in the hope that it will be useful,
13 | # but WITHOUT ANY WARRANTY; without even the implied warranty of
14 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 | # GNU General Public License for more details.
16 | #
17 | # You should have received a copy of the GNU General Public License
18 | # along with bashsrc. If not, see .
19 |
20 | [ -v __ARRAY_SH__ ] && return 0
21 |
22 | readonly __ARRAY_SH__=1
23 |
24 | source builtin.sh
25 |
26 | # .FUNCTION array.len -> [uint]|[bool]
27 | #
28 | # Retorna o total de elementos contidos no array.
29 | #
30 | function array.len()
31 | {
32 | getopt.parse 1 "obj:array:$1" "${@:2}"
33 |
34 | local -n __ref__=$1
35 | echo ${#__ref__[@]}
36 | return $?
37 | }
38 |
39 | # .FUNCTION array.append -> [bool]
40 | #
41 | # Anexa o elemento ao final do array.
42 | #
43 | function array.append()
44 | {
45 | getopt.parse 2 "obj:array:$1" "expr:str:$2" "${@:3}"
46 |
47 | local -n __ref__=$1
48 | __ref__+=("$2")
49 | return $?
50 | }
51 |
52 | # .FUNCTION array.clear -> [bool]
53 | #
54 | # Apaga todos os elementos do container.
55 | #
56 | function array.clear()
57 | {
58 | getopt.parse 2 "obj:array:$1" "${@:2}"
59 |
60 | unset $1
61 | return $?
62 | }
63 |
64 | # .FUNCTION array.clone -> [bool]
65 | #
66 | # Copia os elementos de origem para o container de destino
67 | # sobrescrevendo os elementos já existentes.
68 | #
69 | # == EXEMPLO ==
70 | #
71 | # source array.sh
72 | #
73 | # arr1=(item1 item2 item3)
74 | # arr2=(item4 item5 item6)
75 | #
76 | # echo 'arr1 ->' ${arr1[@]}
77 | # echo 'arr2 ->' ${arr2[@]}
78 | # echo ---
79 | #
80 | # array.clone arr1 arr2
81 | # echo 'arr2 ->' ${arr2[@]}
82 | #
83 | # == SAÍDA ==
84 | #
85 | # arr1 -> item1 item2 item3
86 | # arr2 -> item4 item5 item6
87 | # ---
88 | # arr2 -> item1 item2 item3
89 | #
90 | function array.clone()
91 | {
92 | getopt.parse 2 "src:array:$1" "dest:array:$2" "${@:3}"
93 |
94 | local -n __ref1__=$1 __ref2__=$2
95 | __ref2__=("${__ref1__[@]}")
96 | return $?
97 | }
98 |
99 | # .FUNCTION array.copy -> [bool]
100 | #
101 | # Anexa os elementos de origem no container de destino.
102 | #
103 | function array.copy()
104 | {
105 | getopt.parse 2 "src:array:$1" "dest:array:$2" "${@:3}"
106 |
107 | local -n __ref1__=$1 __ref2__=$2
108 | __ref2__+=("${__ref1__[@]}")
109 | return $?
110 | }
111 |
112 | # .FUNCTION array.count -> [uint]|[bool]
113 | #
114 | # Retorna a quantidade de ocorrências do elemento no container.
115 | #
116 | # == EXEMPLO ==
117 | #
118 | # source array.sh
119 | #
120 | # arr=(item1 item2 item1 item1 item6 item7 item8)
121 | # array.count arr 'item1'
122 | #
123 | # == SAÍDA ==
124 | #
125 | # 3
126 | #
127 | function array.count()
128 | {
129 | getopt.parse 2 "obj:array:$1" "expr:str:$2" "${@:3}"
130 |
131 | local -n __ref__=$1
132 | local __c__ __elem__
133 |
134 | for __elem__ in "${__ref__[@]}"; do
135 | [[ $__elem__ == $2 ]] && ((++__c__))
136 | done
137 |
138 | echo ${__c__:-0}
139 |
140 | return $?
141 | }
142 |
143 | # .FUNCTION array.items -> [str]|[bool]
144 | #
145 | # Retorna uma lista iterável dos elementos contidos no container.
146 | #
147 | function array.items()
148 | {
149 | getopt.parse 1 "obj:array:$1" "${@:2}"
150 |
151 | local -n __ref__=$1
152 | printf '%s\n' "${__ref__[@]}"
153 |
154 | return $?
155 | }
156 |
157 | # .FUNCTION array.index -> [int]|[bool]
158 | #
159 | # Retorna o índice do elemento no container.
160 | #
161 | function array.index()
162 | {
163 | getopt.parse 2 "obj:array:$1" "expr:str:$2" "${@:3}"
164 |
165 | local -n __ref__=$1
166 | local __ind__ __pos__
167 |
168 | for __ind__ in ${!__ref__[@]}; do
169 | [[ ${__ref__[$__ind__]} == $2 ]] &&
170 | __pos__=$__ind__ &&
171 | break
172 | done
173 |
174 | echo ${__pos__:--1}
175 |
176 | return $?
177 | }
178 |
179 | # .FUNCTION array.insert -> [bool]
180 | #
181 | # Insere o elemento no índice do container, reidexando os elementos subsequentes
182 | # a partir do índice especificado.
183 | #
184 | # == EXEMPLO ==
185 | #
186 | # source array.sh
187 | #
188 | # arr=(item1 item2 item4 item5)
189 | # echo ${arr[@]}
190 | #
191 | # array.insert arr 3 'item3'
192 | # echo ${arr[@]}
193 | #
194 | # == SAÍDA ==
195 | #
196 | # item1 item2 item4 item5
197 | # item1 item2 item3 item4 item5
198 | #
199 | function array.insert()
200 | {
201 | getopt.parse 3 "obj:array:$1" "index:uint:$2" "expr:str:$3" "${@:4}"
202 |
203 | local -n __ref__=$1
204 | __ref__=("${__ref__[@]:0:$2}" [$2]="$3" "${__ref__[@]:$2}")
205 |
206 | return $?
207 | }
208 |
209 | # .FUNCTION array.pop -> [str]|[bool]
210 | #
211 | # Retorna e remove o elemento do indice especificado. Utilize notação negativa
212 | # para deslocamento reverso.
213 | #
214 | # == EXEMPLO ==
215 | #
216 | # source array.sh
217 | #
218 | # arr=(item1 item2 item3 item4 item5)
219 | #
220 | # echo "arr ->" ${arr[@]}
221 | # echo ---
222 | # array.pop arr 0 # Primeiro
223 | # array.pop arr -1 # ùltimo
224 | # echo ---
225 | # echo "arr ->" ${arr[@]}
226 | #
227 | # == SAÍDA ==
228 | #
229 | # arr -> item1 item2 item3 item4 item5
230 | # ---
231 | # item1
232 | # item5
233 | # ---
234 | # arr -> item2 item3 item4
235 | #
236 | function array.pop()
237 | {
238 | getopt.parse 2 "obj:array:$1" "index:int:$2" "${@:3}"
239 |
240 | local -n __ref__=$1
241 |
242 | echo "${__ref__[$2]}"
243 | unset __ref__[$2]
244 | return $?
245 | }
246 |
247 | # .FUNCTION array.remove -> [bool]
248 | #
249 | # Remove a primeira ocorrência do elemento.
250 | #
251 | function array.remove()
252 | {
253 | getopt.parse 2 "obj:array:$1" "expr:str:$2" "${@:3}"
254 |
255 | local -n __ref__=$1
256 | local __i__
257 |
258 | for __i__ in ${!__ref__[@]}; do
259 | [[ ${__ref__[$__i__]} == $2 ]] &&
260 | unset __ref__[$__i__] && break
261 | done
262 |
263 | return $?
264 | }
265 |
266 | # .FUNCTION array.reverse -> [bool]
267 | #
268 | # Inverte a ordem dos elementos.
269 | #
270 | # == EXEMPLO ==
271 | #
272 | # source array.sh
273 | #
274 | # arr=(item1 item2 item3 item4 item5)
275 | #
276 | # echo ${arr[@]}
277 | # array.reverse arr
278 | # echo ${arr[@]}
279 | #
280 | # == SAÍDA ==
281 | #
282 | # item1 item2 item3 item4 item5
283 | # item5 item4 item3 item2 item1
284 | #
285 | function array.reverse()
286 | {
287 | getopt.parse 1 "obj:array:$1" "${@:2}"
288 |
289 | local -n __ref__=$1
290 |
291 | mapfile -t $1 < <(printf '%s\n' "${__ref__[@]}" | tac)
292 | return $?
293 | }
294 |
295 | # .FUNCTION array.sort -> [str]|[bool]
296 | #
297 | # Define os elementos em uma ordem ascendente.
298 | #
299 | function array.sort()
300 | {
301 | getopt.parse 1 "obj:array:$1" "${@:2}"
302 |
303 | local -n __ref__=$1
304 |
305 | mapfile -t $1 < <(printf '%s\n' "${__ref__[@]}" | sort -d)
306 | return $?
307 | }
308 |
309 | # .FUNCTION array.join -> [str]|[bool]
310 | #
311 | # Retorna uma string que é a concatenação das strings no iterável
312 | # com o separador especificado.
313 | #
314 | function array.join()
315 | {
316 | getopt.parse 2 "obj:array:$1" "expr:str:$2" "${@:3}"
317 |
318 | local -n __ref__=$1
319 | local __tmp__
320 |
321 | printf -v __tmp__ "%s${2//%/%%}" "${__ref__[@]}"
322 | echo "${__tmp__%$2}"
323 |
324 | return $?
325 | }
326 |
327 | # .FUNCTION array.item -> [str]|[bool]
328 | #
329 | # Retorna o elemento armazenado no índice especificado.
330 | # > Utilize notação negativa para deslocamento reverso.
331 | #
332 | function array.item()
333 | {
334 | getopt.parse 2 "obj:array:$1" "index:int:$2" "${@:3}"
335 |
336 | local -n __ref__=$1
337 | echo "${__ref__[$2]}"
338 |
339 | return $?
340 | }
341 |
342 | # .FUNCTION array.contains -> [bool]
343 | #
344 | # Retorna 'true' se contém o elemento, caso contrário 'false'.
345 | #
346 | function array.contains()
347 | {
348 | getopt.parse 2 "obj:array:$1" "expr:str:$2" "${@:3}"
349 |
350 | local -n __ref__=$1
351 | local __item__
352 |
353 | for __item__ in "${__ref__[@]}"; do
354 | [[ $__item__ == $2 ]] && break
355 | done
356 |
357 | return $?
358 | }
359 |
360 | # .FUNCTION array.reindex -> [bool]
361 | #
362 | # Realiza a reindexação dos elementos.
363 | #
364 | function array.reindex()
365 | {
366 | getopt.parse 1 "obj:array:$1" "${@:2}"
367 |
368 | local -n __ref__=$1
369 |
370 | __ref__=("${__ref__[@]}")
371 | return $?
372 | }
373 |
374 | # .FUNCTION array.slice -> [str]|[bool]
375 | #
376 | # Retorna uma substring resultante do elemento dentro de um container.
377 | # O Slice é a representação do índice e intervalo que deve respeitar
378 | # o seguinte formato:
379 | #
380 | # [start:len]...
381 | #
382 | # start - Índice ou posição do elemento dentro do container.
383 | # len - comprimento a ser capturado a partir de 'start'.
384 | #
385 | # > Não pode conter espaços entre slices.
386 | # > Utilize notação negativa para deslocamento reverso.
387 | #
388 | # Pode ser especificado mais de um slice na expressão, onde o primeiro slice
389 | # representa a posição do elemento dentro do container e os slices subsequentes
390 | # o intervalo da cadeia de caracteres a ser capturada.
391 | #
392 | # == EXEMPLO ==
393 | #
394 | # source array.sh
395 | #
396 | # arr=('Debian' 'Ubuntu' 'Manjaro' 'Fedora')
397 | #
398 | # array.slice arr '[0][:3]' # Os três primeiros caracteres do 1º elemento'
399 | # array.slice arr '[1][3:]' # Os três últimos caracteres do 2º elemento.
400 | # array.slice arr '[2][3:2]' # Os dois caracteres a partir da posição '3' do 3º elemento.
401 | # array.slice arr '[-1][:-2]' # O último elemento exceto os dois últimos caracteres.
402 | # array.slice arr '[:2]' # Os dois primeiros elementos.
403 | #
404 | # == SAÍDA ==
405 | #
406 | # Deb
407 | # ntu
408 | # ja
409 | # Fedo
410 | # Debian
411 | # Ubuntu
412 | #
413 | function array.slice()
414 | {
415 | getopt.parse 2 "obj:array:$1" "slice:str:$2" "${@:3}"
416 |
417 | [[ $2 =~ ${__BUILTIN__[slice]} ]] || error.fatal "'$2' erro de sintaxe na expressão slice"
418 |
419 | local -n __ref__=$1
420 | local __slice__=$2
421 | local __arr__=("${__ref__[@]}")
422 | local __ini__ __len__
423 |
424 | while [[ $__slice__ =~ \[([^]]+)\] ]]; do
425 | IFS=':' read __ini__ __len__ <<< ${BASH_REMATCH[1]}
426 |
427 | __ini__=${__ini__:-0}
428 |
429 | [[ ${BASH_REMATCH[1]} != *@(:)* ]] && __len__=1
430 |
431 | # array
432 | if [[ ${#__arr__[@]} -gt 1 ]]; then
433 | [[ $__len__ -lt 0 ]] && __arr__=() && break
434 | __len__=${__len__:-$((${#__arr__[@]}-$__ini__))}
435 | __arr__=("${__arr__[@]:$__ini__:$__len__}")
436 | else
437 | # string
438 | [[ ${__len__#-} -gt ${#__arr__} ]] && __arr__='' && break
439 | __len__=${__len__:-$((${#__arr__}-$__ini__))}
440 | __arr__=${__arr__:$__ini__:$__len__}
441 | fi
442 | __slice__=${__slice__/\[${BASH_REMATCH[1]}\]/}
443 | done
444 |
445 | printf '%s\n' "${__arr__[@]}"
446 |
447 | return $?
448 | }
449 |
450 | # .FUNCTION array.listindex -> [uint]
451 | #
452 | # Retorna o índice dos elementos.
453 | #
454 | function array.listindex()
455 | {
456 | getopt.parse 1 "obj:array:$1" "${@:2}"
457 |
458 | local -n __ref__=$1
459 | echo ${!__ref__[@]}
460 | return $?
461 | }
462 |
463 | # .FUNCTION array.list -> [uint|str]|[bool]
464 | #
465 | # Retorna uma lista iterável dos elementos e seus respectivos
466 | # indices no seguinte formato:
467 | #
468 | # index|item
469 | #
470 | function array.list()
471 | {
472 | getopt.parse 1 "obj:array:$1" "${@:2}"
473 |
474 | local -n __ref__=$1
475 | local __i__
476 |
477 | for __i__ in ${!__ref__[@]}; do
478 | echo "$__i__|${__ref__[$__i__]}"
479 | done
480 |
481 | return $?
482 | }
483 |
484 | # .TYPE array_t
485 | #
486 | # Implementa o objeto 'S' com os métodos:
487 | #
488 | # S.len
489 | # S.append
490 | # S.clear
491 | # S.clone
492 | # S.copy
493 | # S.count
494 | # S.items
495 | # S.index
496 | # S.insert
497 | # S.pop
498 | # S.remove
499 | # S.reverse
500 | # S.sort
501 | # S.join
502 | # S.item
503 | # S.contains
504 | # S.reindex
505 | # S.slice
506 | # S.listindex
507 | # S.list
508 | #
509 | typedef array_t \
510 | array.len \
511 | array.append \
512 | array.clear \
513 | array.clone \
514 | array.copy \
515 | array.count \
516 | array.items \
517 | array.index \
518 | array.insert \
519 | array.pop \
520 | array.remove \
521 | array.reverse \
522 | array.sort \
523 | array.join \
524 | array.item \
525 | array.contains \
526 | array.reindex \
527 | array.slice \
528 | array.listindex \
529 | array.list
530 |
531 | readonly -f array.len \
532 | array.append \
533 | array.clear \
534 | array.clone \
535 | array.copy \
536 | array.count \
537 | array.items \
538 | array.index \
539 | array.insert \
540 | array.pop \
541 | array.remove \
542 | array.reverse \
543 | array.sort \
544 | array.join \
545 | array.item \
546 | array.contains \
547 | array.reindex \
548 | array.slice \
549 | array.listindex \
550 | array.list
551 |
552 | # /* __ARRAY_SH__ */
553 |
--------------------------------------------------------------------------------
/src/cpu.sh:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 |
3 | # Copyright 2018 Juliano Santos [SHAMAN]
4 | #
5 | # This file is part of bashsrc.
6 | #
7 | # bashsrc is free software: you can redistribute it and/or modify
8 | # it under the terms of the GNU General Public License as published by
9 | # the Free Software Foundation, either version 3 of the License, or
10 | # (at your option) any later version.
11 | #
12 | # bashsrc is distributed in the hope that it will be useful,
13 | # but WITHOUT ANY WARRANTY; without even the implied warranty of
14 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 | # GNU General Public License for more details.
16 | #
17 | # You should have received a copy of the GNU General Public License
18 | # along with bashsrc. If not, see .
19 |
20 | [ -v __CPU_SH__ ] && return 0
21 |
22 | readonly __CPU_SH__=1
23 |
24 | source builtin.sh
25 |
26 | # .FUNCTION cpu.getinfo -> [bool]
27 | #
28 | # Obtem informações do processador,
29 | #
30 | # == EXEMPLO ==
31 | #
32 | # source cpu.sh
33 | #
34 | # # Inicializa o map
35 | # declare -A info=()
36 | #
37 | # # Obtendo informações.
38 | # cpu.getinfo info
39 | #
40 | # # Listando informações.
41 | # echo ${info[processor[0]]}
42 | # echo ${info[model_name[0]]}
43 | # echo ${info[cpu_mhz[0]]}
44 | # echo ---
45 | # echo ${info[processor[1]]}
46 | # echo ${info[model_name[1]]}
47 | # echo ${info[cpu_mhz[1]]}
48 | #
49 | # == SAÍDA ==
50 | #
51 | # 0
52 | # Intel(R) Core(TM) i5-3330 CPU @ 3.00GHz
53 | # 1961.110
54 | # ---
55 | # 1
56 | # Intel(R) Core(TM) i5-3330 CPU @ 3.00GHz
57 | # 1875.432
58 | #
59 | function cpu.getinfo()
60 | {
61 | getopt.parse 1 "cpuinfo:map:$1" "${@:2}"
62 |
63 | local __flag__ __value__ __info__
64 | local __i__=-1
65 | local -n __ref__=$1
66 |
67 | # Inicializar.
68 | __ref__=() || return 1
69 |
70 | while IFS=':' read __flag__ __value__; do
71 | __flag__=${__flag__//@($'\t')}
72 | __flag__=${__flag__// /_}
73 | __flag__=${__flag__,,}
74 | __value__=${__value__##+( )}
75 | case $__flag__ in
76 | processor) ((++__i__));;
77 | '') continue;;
78 | esac
79 | # Atribui o valor da chave.
80 | __ref__[$__flag__[$__i__]]=$__value__
81 | done < /proc/cpuinfo || error.error "'/proc/cpuinfo' não foi possível ler o arquivo"
82 |
83 | return $?
84 | }
85 |
86 | # .MAP cpuinfo
87 | #
88 | # Chaves:
89 | #
90 | # address_sizes[N]
91 | # apicid[N]
92 | # bogomips[N]
93 | # bugs[N]
94 | # cache_alignment[N]
95 | # cache_size[N]
96 | # clflush_size[N]
97 | # core_id[N]
98 | # cpu_cores[N]
99 | # cpu_family[N]
100 | # cpuid_level[N]
101 | # cpu_mhz[N]
102 | # flags[N]
103 | # fpu[N]
104 | # fpu_exception[N
105 | # initial_apicid[N]
106 | # microcode[N]
107 | # model[N]
108 | # model_name[N]
109 | # physical_id[N]
110 | # power_management[N]
111 | # processor[N]
112 | # siblings[N]
113 | # stepping[N]
114 | # vendor_id[N]
115 | # wp[N]
116 | #
117 | # > 'N' é o índice do elemento.
118 | #
119 |
120 | readonly -f cpu.getinfo
121 |
122 | # /* _CPU_SH__ */
123 |
--------------------------------------------------------------------------------
/src/error.sh:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 |
3 | # Copyright 2018 Juliano Santos [SHAMAN]
4 | #
5 | # This file is part of bashsrc.
6 | #
7 | # bashsrc is free software: you can redistribute it and/or modify
8 | # it under the terms of the GNU General Public License as published by
9 | # the Free Software Foundation, either version 3 of the License, or
10 | # (at your option) any later version.
11 | #
12 | # bashsrc is distributed in the hope that it will be useful,
13 | # but WITHOUT ANY WARRANTY; without even the implied warranty of
14 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 | # GNU General Public License for more details.
16 | #
17 | # You should have received a copy of the GNU General Public License
18 | # along with bashsrc. If not, see .
19 |
20 | [ -v __ERROR_SH__ ] && return 0
21 |
22 | readonly __ERROR_SH__=1
23 |
24 | source builtin.sh
25 |
26 | # .FUNCTION error.fatal -> [str]|[bool]
27 | #
28 | # Retorna uma mensagem de erro e finaliza o script com status '1'.
29 | #
30 | function error.fatal()
31 | {
32 | getopt.parse 1 "error:str:$1" "${@:2}"
33 |
34 | echo "erro: linha ${BASH_LINENO[-2]:--}: ${FUNCNAME[-2]:--}: ${1:-fatal}" 1>&2
35 | exit 1
36 | }
37 |
38 | # .FUNCTION error.fatalf ... -> [str]|[bool]
39 | function error.fatalf()
40 | {
41 | getopt.parse -1 "fmt:str:$1" "args:str:$2" ... "${@:3}"
42 |
43 | printf "erro: linha %d: %s: ${1:-fatal}" \
44 | "${BASH_LINENO[-2]:--}" \
45 | "${FUNCNAME[-2]:--}" \
46 | "${@:2}" 1>&2
47 |
48 | exit 1
49 | }
50 |
51 | # .FUNCTION error.error -> [str]|[bool]
52 | function error.error()
53 | {
54 | getopt.parse 1 "error:str:$1" "${@:2}"
55 |
56 | echo "${FUNCNAME[-2]:--}: ${1:-error}" 1>&2
57 | return 1
58 | }
59 |
60 | # .FUNCTION error.errorf ... -> [str]|[bool]
61 | function error.errorf()
62 | {
63 | getopt.parse -1 "fmt:str:$1" "args:str:$2" ... "${@:3}"
64 |
65 | printf "${FUNCNAME[-2]:--}: ${1:-error}" "${@:2}" 1>&2
66 | return 1
67 | }
68 |
69 | # .FUNCTION error.warn -> [str]|[bool]
70 | function error.warn()
71 | {
72 | getopt.parse 1 "error:str:$1" "${@:2}"
73 |
74 | echo -e "\e[0;31m${FUNCNAME[-2]:--}: ${1:-warn}\e[0;m" 1>&2
75 | return 1
76 | }
77 |
78 | # .FUNCTION error.warnf ... -> [str]|[bool]
79 | function error.warnf()
80 | {
81 | getopt.parse -1 "error:str:$1" "args:str:$2" ... "${@:3}"
82 |
83 | printf "\e[0;31m${FUNCNAME[-2]:--}: ${1:-warn}\e[0;m" "${@:2}" 1>&2
84 | return 1
85 | }
86 |
87 | # .TYPE error_t
88 | #
89 | # Implementa o objeto 'S' com os métodos:
90 | #
91 | # S.fatal
92 | # S.fatalf
93 | # S.error
94 | # S.errorf
95 | # S.warn
96 | # S.warnf
97 | #
98 | typedef error_t \
99 | error.fatal \
100 | error.fatalf \
101 | error.error \
102 | error.errorf \
103 | error.warn \
104 | error.warnf
105 |
106 | readonly -f error.fatal \
107 | error.fatalf \
108 | error.error \
109 | error.errorf \
110 | error.warn \
111 | error.warnf
112 |
113 | # /* __ERROR_SH__ */
114 |
--------------------------------------------------------------------------------
/src/getopt.sh:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 |
3 | # Copyright 2018 Juliano Santos [SHAMAN]
4 | #
5 | # This file is part of bashsrc.
6 | #
7 | # bashsrc is free software: you can redistribute it and/or modify
8 | # it under the terms of the GNU General Public License as published by
9 | # the Free Software Foundation, either version 3 of the License, or
10 | # (at your option) any later version.
11 | #
12 | # bashsrc is distributed in the hope that it will be useful,
13 | # but WITHOUT ANY WARRANTY; without even the implied warranty of
14 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 | # GNU General Public License for more details.
16 | #
17 | # You should have received a copy of the GNU General Public License
18 | # along with bashsrc. If not, see .
19 |
20 | [ -v __GETOPT_SH__ ] && return 0
21 |
22 | readonly __GETOPT_SH__=1
23 |
24 | source builtin.sh
25 |
26 | # Protótipos.
27 | readonly -A __GETOPT__=(
28 | [parse]='\bgetopt\.parse\s-?[0-9]+\s"[^:]+:'
29 | [arg]=${__BUILTIN__[varname]}
30 | [type]=${__BUILTIN__[vartype]}
31 | [nargs]='^(-1|0|[1-9][0-9]*)$'
32 | [funcs]='^getopt\.(n?args|values?|types?|params)$'
33 | )
34 |
35 | # Global
36 | declare -ag __GETOPT_PARSE__
37 |
38 | # .FUNCTION getopt.parse ... -> [bool]
39 | #
40 | # Define e processa 'N' argumentos posicionais na linha de comando.
41 | # Retorna 'true' se todos os argumentos satisfazem os tipos estabelecidos,
42 | # caso contrário retorna 'false' e finaliza o script com status '1'.
43 | #
44 | # nargs - Número de argumentos suportados.
45 | # Se 'nargs = -1' ativa o suporte a argumentos variádicos. Utilize
46 | # '...' para determinar o argumento posicional variádico.
47 | #
48 | # O argumento passado na função é constituído por uma cadeia de caracteres
49 | # que determina o nome, tipo e valor do argumento posicional a ser
50 | # processado, e que precisa respeitar a seguinte sintaxe:
51 | #
52 | # arg:type:value
53 | #
54 | # arg - Nome do argumento posicional cujo caracteres suportados são: '[a-zA-Z0-9_]'
55 | # e deve iniciar com pelo menos uma letra ou underline '_'.
56 | # type - Tipo do dado suportado pelo argumento. O identificador deve ser um objeto
57 | # válido ou um tipo 'builtin'.
58 | # value - Valor do argumento posicional.
59 | #
60 | # Tipos (builtin):
61 | #
62 | # bool - true ou false.
63 | # str - Uma cadeia de caracteres.
64 | # char - Um caractere.
65 | # int - Inteiro.
66 | # uint - Inteiro positivo (sem sinal).
67 | # float - Números com valor de ponto flutuante.
68 | # var - Identificador de uma variável.
69 | # array - Identificador de um array válido.
70 | # map - Identificador de um array associativo válido.
71 | # function - Identificador de uma função válida.
72 | #
73 | # Exemplos:
74 | #
75 | # -- PADRÃO --
76 | #
77 | # argumentos posicionais
78 | # |
79 | # -----------------
80 | # | |
81 | # getopt.parse 2 "arg1:type1:$1" "arg2:type2:$2" "${@:3}"
82 | # | |
83 | # total argumentos
84 | # argumentos subsequentes
85 | # (total + 1)
86 | #
87 | # -- VARIÁDICA --
88 | #
89 | # getopt.parse -1 "arg1:type1:$1" "arg2:type2:$2" ... "${@:3}"
90 | # | | | | |
91 | # variádica ---------------- |
92 | # | |
93 | # argumento argumentos
94 | # variádico subsequentes
95 | #
96 | # > Os argumentos subsequentes ao variático herdão seus atributos (exceto: valor).
97 | #
98 | function getopt.parse()
99 | {
100 | local arg args ntype type val param flag vparam vp fl
101 |
102 | [[ $1 =~ ${__GETOPT__[nargs]} ]] || error.fatal "'$1' número de argumentos inválido"
103 | [[ $1 -ge 0 && $((${#@}-1)) -gt $1 ]] && error.fatal "'${*:$1+2}' excesso de argumentos"
104 |
105 | # Limpa memória. (exceto: funções 'getopt')
106 | [[ ${FUNCNAME[1]} =~ ${__GETOPT__[funcs]} ]] || __GETOPT_PARSE__=()
107 |
108 | # Lê os argumentos posicionais.
109 | for param in "${@:2}"; do
110 | # Se a função conter argumentos variáticos, define o argumento atual
111 | # com os atributos do último argumento.
112 | [[ $vp ]] && param=$vparam:$param
113 | [[ $param == ... && $1 -eq -1 ]] && vp=1 && continue # Define a função como variática.
114 |
115 | IFS=':' read -r arg ntype val <<< "$param"
116 |
117 | [[ ! $vp && $arg == @($args) ]] && error.fatal "'$arg' conflito de argumentos"
118 |
119 | # Extrai tipo.
120 | type=${ntype%%[*}
121 |
122 | [[ $arg =~ ${__GETOPT__[arg]} ]] || error.fatal "'$arg' nome do argumento inválido"
123 | [[ $ntype =~ ${__GETOPT__[type]} ]] || error.fatal "'$ntype' erro de sintaxe"
124 | [[ $type == @(${__ALL_TYPE_NAMES__// /|}) ]] || error.fatal "'$type' tipo do objeto desconhecido"
125 |
126 | # Flag de validação.
127 | flag=${__BUILTIN_TYPES__[$type]}
128 |
129 | # Avalia o valor do argumento com base no tipo especificado.
130 | case $type in
131 | # Insira aqui os tipos especiais que requerem premissas de avaliação e critérios
132 | # que determinam o tipo do objeto. É dado como válido se o retorno de status da
133 | # última instrução for 'verdadeira', caso contrário uma mensagem de erro é
134 | # apresentada e a rotina finalizada com status 1.
135 | var) [[ $val =~ ${__BUILTIN__[vartype]} ]];;
136 | array) IFS=' ' read _ fl _ <<< $(declare -p $val 2>/dev/null); [[ $fl == *a* ]];;
137 | map) IFS=' ' read _ fl _ <<< $(declare -p $val 2>/dev/null); [[ $fl == *A* ]];;
138 | function) [[ $type == $(type -t $val) ]];;
139 | *) if [[ $flag && $val =~ $flag ]]; then :
140 | elif [[ $type == ${__OBJ_INIT__[${val:--}]%%|*} ]]; then
141 | [[ $ntype =~ ${__GETOPT__[type]} ]]
142 | [[ ! ${BASH_REMATCH[2]} && $(sizeof $val) -eq 0 ]] ||
143 | [[ ${BASH_REMATCH[2]} == [] && $(sizeof $val) -gt 0 ]] ||
144 | [[ ${BASH_REMATCH[3]} == $(sizeof $val) ]]
145 | else false
146 | fi
147 | ;;
148 | esac || error.fatal "<$arg[$ntype]>: '$val' tipo do dado inválido"
149 |
150 | # Salva a linha de comando.
151 | __GETOPT_PARSE__+=("$param")
152 |
153 | # Salva atributos.
154 | vparam=$arg:$type
155 | args+=${args:+|}${arg}
156 | done
157 |
158 | return $?
159 | }
160 |
161 | # .FUNCTION getopt.nargs -> [uint]|[bool]
162 | #
163 | # Retorna o total de argumentos
164 | #
165 | function getopt.nargs()
166 | {
167 | getopt.parse 0 "$@"
168 |
169 | echo ${#__GETOPT_PARSE__[@]}
170 | return $?
171 | }
172 |
173 | # .FUNCTION getopt.args -> [str]|[bool]
174 | #
175 | # Retorna o nome dos argumentos posicionais.
176 | #
177 | function getopt.args()
178 | {
179 | getopt.parse 0 "$@"
180 |
181 | local param arg
182 | for param in "${__GETOPT_PARSE__[@]}"; do
183 | IFS=':' read arg _ _ <<< "$param"
184 | echo "$arg"
185 | done
186 | return $?
187 | }
188 |
189 | # .FUNCTION getopt.types -> [str]|[bool]
190 | #
191 | # Retorna o tipo dos argumentos posicionais.
192 | #
193 | function getopt.types()
194 | {
195 | getopt.parse 0 "$@"
196 |
197 | local param type
198 | for param in "${__GETOPT_PARSE__[@]}"; do
199 | IFS=':' read _ type _ <<< "$param"
200 | echo "$type"
201 | done
202 | return $?
203 | }
204 |
205 | # .FUNCTION getopt.values -> [str]|[bool]
206 | #
207 | # Retorna o valor dos argumentos posicionais.
208 | #
209 | function getopt.values()
210 | {
211 | getopt.parse 0 "$@"
212 |
213 | local param val
214 | for param in "${__GETOPT_PARSE__[@]}"; do
215 | IFS=':' read -r _ _ val <<< "$param"
216 | echo "$val"
217 | done
218 | return $?
219 | }
220 |
221 | # .FUNCTION getopt.params -> [str|str]|[bool]
222 | #
223 | # Retorna uma string com os atributos dos argumentos
224 | # posicionais no seguinte formato:
225 | #
226 | # arg|type
227 | #
228 | function getopt.params()
229 | {
230 | getopt.parse 0 "$@"
231 |
232 | local param arg type
233 | for param in "${__GETOPT_PARSE__[@]}"; do
234 | IFS=':' read arg type _ <<< "$param"
235 | echo "$arg|$type"
236 | done
237 | return $?
238 | }
239 |
240 | # .FUNCTION getopt.value -> [str]|[bool]
241 | #
242 | # Retorna o valor do argumento especificado.
243 | #
244 | function getopt.value()
245 | {
246 | getopt.parse 1 "argname:str:$1" "${@:2}"
247 |
248 | local param arg val
249 | for param in "${__GETOPT_PARSE__[@]}"; do
250 | IFS=':' read -r arg _ val <<< "$param"
251 | [[ $arg == $1 ]] && echo "$val"
252 | done
253 | return $?
254 | }
255 |
256 | # .FUNCTION getopt.type -> [str]|[bool]
257 | #
258 | # Retorna o tipo do argumento especificado.
259 | #
260 | function getopt.type()
261 | {
262 | getopt.parse 1 "argname:str:$1" "${@:2}"
263 |
264 | local param arg type
265 | for param in "${__GETOPT_PARSE__[@]}"; do
266 | IFS=':' read arg type _ <<< "$param"
267 | [[ $arg == $1 ]] && echo "$type"
268 | done
269 | return $?
270 | }
271 |
272 | readonly -f getopt.parse \
273 | getopt.nargs \
274 | getopt.args \
275 | getopt.types \
276 | getopt.values \
277 | getopt.params \
278 | getopt.value \
279 | getopt.type
280 |
281 | # /* __GETOPT_SH__ */
282 |
--------------------------------------------------------------------------------
/src/grp.sh:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 |
3 | # Copyright 2018 Juliano Santos [SHAMAN]
4 | #
5 | # This file is part of bashsrc.
6 | #
7 | # bashsrc is free software: you can redistribute it and/or modify
8 | # it under the terms of the GNU General Public License as published by
9 | # the Free Software Foundation, either version 3 of the License, or
10 | # (at your option) any later version.
11 | #
12 | # bashsrc is distributed in the hope that it will be useful,
13 | # but WITHOUT ANY WARRANTY; without even the implied warranty of
14 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 | # GNU General Public License for more details.
16 | #
17 | # You should have received a copy of the GNU General Public License
18 | # along with bashsrc. If not, see .
19 |
20 | [ -v __GRP_SH__ ] && return 0
21 |
22 | readonly __GRP_SH__=1
23 |
24 | source builtin.sh
25 |
26 | # .FUNCTION grp.getgroups -> [uint]|[bool]
27 | #
28 | # Retorna os IDs de grupo suplementares da chamada do processo.
29 | #
30 | function grp.getgroups()
31 | {
32 | getopt.parse 0 "$@"
33 |
34 | printf '%s\n' ${GROUPS[@]}
35 | return $?
36 | }
37 |
38 | # .FUNCTION grp.getgrall -> [str]|[bool]
39 | #
40 | # Retorna uma lista com todos os grupos do sistema.
41 | #
42 | function grp.getgrall()
43 | {
44 | getopt.parse 0 "$@"
45 |
46 | local grp
47 |
48 | while IFS=':' read grp _; do
49 | echo $grp
50 | done < /etc/group
51 |
52 | return $?
53 | }
54 |
55 | # .FUNCTION grp.getgrnam -> [bool]
56 | #
57 | # Obtém no banco de dados as informações do grupo especificado.
58 | #
59 | function grp.getgrnam()
60 | {
61 | getopt.parse 2 "name:str:$1" "grp:map:$2" "${@:3}"
62 |
63 | local __name__ __pass__ __gid__ __mem__
64 | local -n __ref__=$2
65 |
66 | __ref__=() || return 1
67 |
68 | while IFS=':' read __name__ \
69 | __pass__ \
70 | __gid__ \
71 | __mem__; do
72 | [[ $1 == $__name__ ]] && break
73 | done < /etc/group
74 |
75 | (($?)) && { error.error "'$1' grupo não encontrado"; return $?; }
76 |
77 | __ref__[gr_name]=$__name__
78 | __ref__[gr_passwd]=$__pass__
79 | __ref__[gr_gid]=$__gid__
80 | __ref__[gr_mem]=$__mem__
81 |
82 | return $?
83 | }
84 |
85 | # .FUNCTION grp.getgrgid -> [bool]
86 | #
87 | # Obtém no banco de dados as informações do id do grupo especificado.
88 | #
89 | function grp.getgrgid()
90 | {
91 | getopt.parse 2 "gid:uint:$1" "grp:map:$2" "${@:3}"
92 |
93 | local __name__ __pass__ __gid__ __mem__
94 | local -n __ref__=$2
95 |
96 | __ref__=() || return 1
97 |
98 | while IFS=':' read __name__ \
99 | __pass__ \
100 | __gid__ \
101 | __mem__; do
102 | [[ $1 == $__gid__ ]] && break
103 | done < /etc/group
104 |
105 | (($?)) && { error.error "'$1' gid não encontrado"; return $?; }
106 |
107 | __ref__[gr_name]=$__name__
108 | __ref__[gr_passwd]=$__pass__
109 | __ref__[gr_gid]=$__gid__
110 | __ref__[gr_mem]=$__mem__
111 |
112 | return $?
113 | }
114 |
115 | # .MAP grp
116 | #
117 | # Chaves:
118 | #
119 | # gr_name /* Nome do grupo */
120 | # gr_passwd /* Senha criptgrafada do grupo ou vazio. */
121 | # gr_gid /* Identificador númerico do grupo */
122 | # gr_mem /* Lista de usuários ou membros do grupos separados por vírgula (,). */
123 | #
124 |
125 | # Funções (somente leitura)
126 | readonly -f grp.getgroups \
127 | grp.getgrall \
128 | grp.getgrnam \
129 | grp.getgrgid
130 |
131 | # /* __GRP_SH__ */
132 |
133 |
--------------------------------------------------------------------------------
/src/http.sh:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 |
3 | # Copyright 2018 Juliano Santos [SHAMAN]
4 | #
5 | # This file is part of bashsrc.
6 | #
7 | # bashsrc is free software: you can redistribute it and/or modify
8 | # it under the terms of the GNU General Public License as published by
9 | # the Free Software Foundation, either version 3 of the License, or
10 | # (at your option) any later version.
11 | #
12 | # bashsrc is distributed in the hope that it will be useful,
13 | # but WITHOUT ANY WARRANTY; without even the implied warranty of
14 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 | # GNU General Public License for more details.
16 | #
17 | # You should have received a copy of the GNU General Public License
18 | # along with bashsrc. If not, see .
19 |
20 | [ -v __HTTP_SH__ ] && return 0
21 |
22 | readonly __HTTP_SH__=1
23 |
24 | source builtin.sh
25 | source struct.sh
26 | source setup.sh
27 |
28 | # Dependência.
29 | setup.package 'curl (>= 7.0)'
30 |
31 | readonly -A __HTTP__=(
32 | [methods]='@(GET|POST|HEAD|PUT|DELETE|CONNECT|OPTIONS|TRACE)'
33 | )
34 |
35 | # .FUNCTION http.get -> [bool]
36 | #
37 | # Envia uma requisição ao servidor e salva a resposta no
38 | # mapa apontado por 'response'.
39 | #
40 | # == EXEMPLO ==
41 | #
42 | # #!/bin/bash
43 | #
44 | # source http.sh
45 | #
46 | # # mapa
47 | # declare -A resp=()
48 | #
49 | # http.get 'ipecho.net/plain' resp
50 | # echo 'IP externo:' ${resp[body]}
51 | #
52 | # == SAÍDA ==
53 | #
54 | # IP externo: 179.72.180.201
55 | #
56 | function http.get()
57 | {
58 | getopt.parse 2 "url:str:$1" "response:map:$2" "${@:3}"
59 |
60 | local __resp__ __header__ __value__ __bodyfile__
61 | local -n __ref__=$2
62 |
63 | __ref__=() || return 1
64 |
65 | # Arquivo temporário que irá armazenar o contéudo da página.
66 | __bodyfile__=$(mktemp -qtu XXXXXXXXXXXXXXXXXXXX)
67 | trap "rm -f $__bodyfile__ 2>/dev/null" SIGINT SIGTERM SIGKILL SIGTSTP RETURN
68 |
69 | while IFS=$'\n' read -r __resp__; do
70 | # Lê os headers de resposta e mapeia as chaves
71 | # com a nomenclatura de cada header processado,
72 | # atribuindo os respectivos valores.
73 | if [ "${__resp__:0:1}" == '<' ]; then
74 | IFS=' ' read -r _ __header__ __value__ <<< "$__resp__"
75 | # Se estiver vazio lê o próximo 'header'.
76 | [[ ! $__value__ ]] && continue
77 | __header__=${__header__%:}
78 | __header__=${__header__,,}
79 | case $__header__ in
80 | http/1.@(0|1)) __ref__[proto]=$__header__
81 | __ref__[status]=${__value__%% *};;
82 | *) __ref__[$__header__]=$__value__;;
83 | esac
84 | fi
85 | done < <(curl -qsvX GET "$1" --output $__bodyfile__ 2>&1)
86 |
87 | # Conteúdo.
88 | __ref__[body]=$(< $__bodyfile__)
89 |
90 | return $?
91 | }
92 |
93 | # .FUNCTION http.request -> [bool]
94 | #
95 | # Envia uma requisição ao servidor com o método HTTP a ser executado no recurso
96 | # com os campos e cabeçalhos especificados na estrutura 'headers' e salva a
97 | # resposta no mapa apontado por 'response'.
98 | #
99 | # HTTP (métodos): OPTIONS, GET, HEAD, POST, PUT, DELETE, TRACE, CONNECT
100 | #
101 | # == EXEMPLO ==
102 | #
103 | # O exemplo a seguir utiliza um modelo simples para envio de mensagens
104 | # via API Telegram.
105 | #
106 | # #!/bin/bash
107 | #
108 | # source http.sh
109 | #
110 | # # API
111 | # url_api='https://api.telegram.org/bot/sendMessage'
112 | #
113 | # # Inicializa os arrays associativos.
114 | # declare -A fields=()
115 | # declare -A resp=()
116 | #
117 | # # Cabeçalho (estrutura)
118 | # var header http_header_st
119 | #
120 | # # Definindo configurações.
121 | # header.accept = 'application/json'
122 | #
123 | # # Campos para requisição do método da api.
124 | # fields[chat_id]=181885983
125 | # fields[text]='Enviando mensagem de teste'
126 | #
127 | # # Envia requisição para o servidor.
128 | # http.request 'POST' "$url_api" fields header resp
129 | #
130 | # # Retorno
131 | # echo "${resp[body]}"
132 | #
133 | # == SAÍDA ==
134 | #
135 | # {"ok":true,"result":{"message_id":44471,"from":{"id":371714654,"is_bot":true,"first_name":"BASHBot","username":"bashxxx_bot"},"chat":{"id":181885983,"first_name":"SHAMAN","username":"x_SHAMAN_x","type":"private"},"date":1547900652,"text":"Enviando mensagem de teste"}}
136 | #
137 | function http.request()
138 | {
139 | getopt.parse 5 "method:str:$1" "url:str:$2" "fields:map:$3" "headers:http_header_st:$4" "response:map:$5" "${@:6}"
140 |
141 | local __field__ __opt__ __bodyfile__ __resp__
142 | local __value__ __header__ __headers__ __re__
143 | local -n __fields__=$3 __ref__=$5
144 |
145 | __ref__=() || return 1
146 |
147 | if [[ $1 != ${__HTTP__[methods]} ]]; then
148 | error.error "'$1' HTTP método inválido"
149 | return 1
150 | fi
151 |
152 | # Arquivo temporário que irá armazenar o contéudo da página.
153 | __bodyfile__=$(mktemp -qtu XXXXXXXXXXXXXXXXXXXX)
154 | trap "rm -f $__bodyfile__ 2>/dev/null" SIGINT SIGTERM SIGKILL SIGTSTP RETURN
155 |
156 | # Verifica se formato do contéudo a ser transmitido é um formulário
157 | # multipart para upload de arquivos e define a opção adequada.
158 | # -d (padrão)
159 | __re__='\bmultipart/form-data\b'
160 | [[ $($4.accept) =~ $__re__ ]] && __opt__='-F'
161 |
162 | # Cabeçalhos.
163 | __headers__=(
164 | [1]=$($4.aim) # a-im
165 | [2]=$($4.accept) # Accept
166 | [3]=$($4.accept_charset) # Accept-Charset
167 | [4]=$($4.accept_encoding) # Accept-Encoding
168 | [5]=$($4.accept_language) # Accept-Language
169 | [6]=$($4.accept_datetime) # Accept-Datetime
170 | [7]=$($4.accept_control_request_method) # Access-Control-Request-Method
171 | [8]=$($4.accept_control_request_headers) # Access-Control-Request-Headers
172 | [9]=$($4.authorization) # Authorization
173 | [10]=$($4.cache_control) # Cache-Control
174 | [11]=$($4.connection) # Connection
175 | [12]=$($4.content_length) # Content-Length
176 | [13]=$($4.content_md5) # Content-MD5
177 | [14]=$($4.content_type) # Content-Type
178 | [15]=$($4.cookie) # Cookie
179 | [16]=$($4.date) # Date
180 | [17]=$($4.expect) # Expect
181 | [18]=$($4.forwarded) # Forwarded
182 | [19]=$($4.from) # From
183 | [20]=$($4.host) # Host
184 | [21]=$($4.http2_settings) # HTTP2-Settings
185 | [22]=$($4.if_match) # If-Match
186 | [23]=$($4.if_modified_since) # If-Modified-Since
187 | [24]=$($4.if_none_match) # If-None-Match
188 | [25]=$($4.if_range) # If-Range
189 | [26]=$($4.if_unmodified_since) # If-Unmodified-Since
190 | [27]=$($4.max_forwards) # Max-Forwards
191 | [28]=$($4.origin) # Origin
192 | [29]=$($4.pragma) # Pragma
193 | [30]=$($4.proxy_authorization) # Proxy-Authorization
194 | [31]=$($4.range) # Range
195 | [32]=$($4.referer) # Referer
196 | [33]=$($4.te) # TE
197 | [34]=$($4.user_agent) # User-Agent
198 | [35]=$($4.upgrade) # Upgrade
199 | [36]=$($4.via) # Via
200 | [37]=$($4.warning) # Warning
201 | )
202 |
203 | while IFS=$'\n' read -r __resp__; do
204 | # Lê os headers de resposta e mapeia as chaves
205 | # com a nomenclatura de cada header processado
206 | # atribuindo os respectivos valores.
207 | if [ "${__resp__:0:1}" == '<' ]; then
208 | IFS=' ' read -r _ __header__ __value__ <<< "$__resp__"
209 | # Se estiver vazio lê o próximo 'header'.
210 | [[ ! $__value__ ]] && continue
211 | __header__=${__header__%:}
212 | __header__=${__header__,,}
213 | case $__header__ in
214 | http/1.@(0|1)) __ref__[proto]=$__header__
215 | __ref__[status]=${__value__%% *};;
216 | *) __ref__[$__header__]=$__value__;;
217 | esac
218 | fi
219 | done < <(
220 | # Converte o mapa contendo os campos em parâmetros de linha de comando
221 | # e envia ao comando 'curl' para processamento com os cabeçalhos definidos.
222 | for __field__ in "${!__fields__[@]}"; do
223 | echo "${__opt__:--d} $__field__='${__fields__[$__field__]}' "
224 | done | xargs -e curl -qsvX $1 "$2" \
225 | ${__headers__[1]:+-H "A-IM: ${__headers__[1]}"} \
226 | ${__headers__[2]:+-H "Accept: ${__headers__[2]}"} \
227 | ${__headers__[3]:+-H "Accept-Charset: ${__headers__[3]}"} \
228 | ${__headers__[4]:+-H "Accept-Encoding: ${__headers__[4]}"} \
229 | ${__headers__[5]:+-H "Accept-Language: ${__headers__[5]}"} \
230 | ${__headers__[6]:+-H "Accept-Datetime: ${__headers__[6]}"} \
231 | ${__headers__[7]:+-H "Access-Control-Request-Method: ${__headers__[7]}"} \
232 | ${__headers__[8]:+-H "Access-Control-Request-Headers: ${__headers__[8]}"} \
233 | ${__headers__[9]:+-H "Authorization: ${__headers__[9]}"} \
234 | ${__headers__[10]:+-H "Cache-Control: ${__headers__[10]}"} \
235 | ${__headers__[11]:+-H "Connection: ${__headers__[11]}"} \
236 | ${__headers__[12]:+-H "Content-Length: ${__headers__[12]}"} \
237 | ${__headers__[13]:+-H "Content-MD5: ${__headers__[13]}"} \
238 | ${__headers__[14]:+-H "Content-Type: ${__headers__[14]}"} \
239 | ${__headers__[15]:+-H "Cookie: ${__headers__[15]}"} \
240 | ${__headers__[16]:+-H "Date: ${__headers__[16]}"} \
241 | ${__headers__[17]:+-H "Expect: ${__headers__[17]}"} \
242 | ${__headers__[18]:+-H "Forwarded: ${__headers__[18]}"} \
243 | ${__headers__[19]:+-H "From: ${__headers__[19]}"} \
244 | ${__headers__[20]:+-H "Host: ${__headers__[20]}"} \
245 | ${__headers__[21]:+-H "HTTP2-Settings: ${__headers__[21]}"} \
246 | ${__headers__[22]:+-H "If-Match: ${__headers__[22]}"} \
247 | ${__headers__[23]:+-H "If-Modified-Since: ${__headers__[23]}"} \
248 | ${__headers__[24]:+-H "If-None-Match: ${__headers__[24]}"} \
249 | ${__headers__[25]:+-H "If-Range: ${__headers__[25]}"} \
250 | ${__headers__[26]:+-H "If-Unmodified-Since: ${__headers__[26]}"} \
251 | ${__headers__[27]:+-H "Max-Forwards: ${__headers__[27]}"} \
252 | ${__headers__[28]:+-H "Origin: ${__headers__[28]}"} \
253 | ${__headers__[29]:+-H "Pragma: ${__headers__[29]}"} \
254 | ${__headers__[30]:+-H "Proxy-Authorization: ${__headers__[30]}"} \
255 | ${__headers__[31]:+-H "Range: ${__headers__[31]}"} \
256 | ${__headers__[32]:+-H "Referer: ${__headers__[32]}"} \
257 | ${__headers__[33]:+-H "TE: ${__headers__[33]}"} \
258 | ${__headers__[34]:+-H "User-Agent: ${__headers__[34]}"} \
259 | ${__headers__[35]:+-H "Upgrade: ${__headers__[35]}"} \
260 | ${__headers__[36]:+-H "Via: ${__headers__[36]}"} \
261 | ${__headers__[37]:+-H "Warning: ${__headers__[37]}"} \
262 | --output $__bodyfile__ 2>&1
263 | )
264 |
265 | # Conteúdo
266 | __ref__[body]=$(< $__bodyfile__)
267 |
268 | return $?
269 | }
270 |
271 | # .FUNCTION http.request_data -> [bool]
272 | #
273 | # Como 'http.request', porém envia uma string contendo uma estrutura de dados.
274 | #
275 | function http.request_data()
276 | {
277 | getopt.parse 5 "method:str:$1" "url:str:$2" "data:str:$3" "headers:http_header_st:$4" "response:map:$5" "${@:6}"
278 |
279 | local __field__ __opt__ __bodyfile__ __resp__
280 | local __value__ __header__ __headers__ __re__
281 | local -n __ref__=$5
282 |
283 | __ref__=() || return 1
284 |
285 | if [[ $1 != ${__HTTP__[methods]} ]]; then
286 | error.error "'$1' HTTP método inválido"
287 | return 1
288 | fi
289 |
290 | # Arquivo temporário que irá armazenar o contéudo da página.
291 | __bodyfile__=$(mktemp -qtu XXXXXXXXXXXXXXXXXXXX)
292 | trap "rm -f $__bodyfile__ 2>/dev/null" SIGINT SIGTERM SIGKILL SIGTSTP RETURN
293 |
294 | # Cabeçalhos.
295 | __headers__=(
296 | [1]=$($4.aim) # a-im
297 | [2]=$($4.accept) # Accept
298 | [3]=$($4.accept_charset) # Accept-Charset
299 | [4]=$($4.accept_encoding) # Accept-Encoding
300 | [5]=$($4.accept_language) # Accept-Language
301 | [6]=$($4.accept_datetime) # Accept-Datetime
302 | [7]=$($4.accept_control_request_method) # Access-Control-Request-Method
303 | [8]=$($4.accept_control_request_headers) # Access-Control-Request-Headers
304 | [9]=$($4.authorization) # Authorization
305 | [10]=$($4.cache_control) # Cache-Control
306 | [11]=$($4.connection) # Connection
307 | [12]=$($4.content_length) # Content-Length
308 | [13]=$($4.content_md5) # Content-MD5
309 | [14]=$($4.content_type) # Content-Type
310 | [15]=$($4.cookie) # Cookie
311 | [16]=$($4.date) # Date
312 | [17]=$($4.expect) # Expect
313 | [18]=$($4.forwarded) # Forwarded
314 | [19]=$($4.from) # From
315 | [20]=$($4.host) # Host
316 | [21]=$($4.http2_settings) # HTTP2-Settings
317 | [22]=$($4.if_match) # If-Match
318 | [23]=$($4.if_modified_since) # If-Modified-Since
319 | [24]=$($4.if_none_match) # If-None-Match
320 | [25]=$($4.if_range) # If-Range
321 | [26]=$($4.if_unmodified_since) # If-Unmodified-Since
322 | [27]=$($4.max_forwards) # Max-Forwards
323 | [28]=$($4.origin) # Origin
324 | [29]=$($4.pragma) # Pragma
325 | [30]=$($4.proxy_authorization) # Proxy-Authorization
326 | [31]=$($4.range) # Range
327 | [32]=$($4.referer) # Referer
328 | [33]=$($4.te) # TE
329 | [34]=$($4.user_agent) # User-Agent
330 | [35]=$($4.upgrade) # Upgrade
331 | [36]=$($4.via) # Via
332 | [37]=$($4.warning) # Warning
333 | )
334 |
335 | while IFS=$'\n' read -r __resp__; do
336 | # Lê os headers de resposta e mapeia as chaves
337 | # com a nomenclatura de cada header processado
338 | # atribuindo os respectivos valores.
339 | if [ "${__resp__:0:1}" == '<' ]; then
340 | IFS=' ' read -r _ __header__ __value__ <<< "$__resp__"
341 | # Se estiver vazio lê o próximo 'header'.
342 | [[ ! $__value__ ]] && continue
343 | __header__=${__header__%:}
344 | __header__=${__header__,,}
345 | case $__header__ in
346 | http/1.@(0|1)) __ref__[proto]=$__header__
347 | __ref__[status]=${__value__%% *};;
348 | *) __ref__[$__header__]=$__value__;;
349 | esac
350 | fi
351 | done < <(curl -qsvX $1 "$2" -d "$3" \
352 | ${__headers__[1]:+-H "A-IM: ${__headers__[1]}"} \
353 | ${__headers__[2]:+-H "Accept: ${__headers__[2]}"} \
354 | ${__headers__[3]:+-H "Accept-Charset: ${__headers__[3]}"} \
355 | ${__headers__[4]:+-H "Accept-Encoding: ${__headers__[4]}"} \
356 | ${__headers__[5]:+-H "Accept-Language: ${__headers__[5]}"} \
357 | ${__headers__[6]:+-H "Accept-Datetime: ${__headers__[6]}"} \
358 | ${__headers__[7]:+-H "Access-Control-Request-Method: ${__headers__[7]}"} \
359 | ${__headers__[8]:+-H "Access-Control-Request-Headers: ${__headers__[8]}"} \
360 | ${__headers__[9]:+-H "Authorization: ${__headers__[9]}"} \
361 | ${__headers__[10]:+-H "Cache-Control: ${__headers__[10]}"} \
362 | ${__headers__[11]:+-H "Connection: ${__headers__[11]}"} \
363 | ${__headers__[12]:+-H "Content-Length: ${__headers__[12]}"} \
364 | ${__headers__[13]:+-H "Content-MD5: ${__headers__[13]}"} \
365 | ${__headers__[14]:+-H "Content-Type: ${__headers__[14]}"} \
366 | ${__headers__[15]:+-H "Cookie: ${__headers__[15]}"} \
367 | ${__headers__[16]:+-H "Date: ${__headers__[16]}"} \
368 | ${__headers__[17]:+-H "Expect: ${__headers__[17]}"} \
369 | ${__headers__[18]:+-H "Forwarded: ${__headers__[18]}"} \
370 | ${__headers__[19]:+-H "From: ${__headers__[19]}"} \
371 | ${__headers__[20]:+-H "Host: ${__headers__[20]}"} \
372 | ${__headers__[21]:+-H "HTTP2-Settings: ${__headers__[21]}"} \
373 | ${__headers__[22]:+-H "If-Match: ${__headers__[22]}"} \
374 | ${__headers__[23]:+-H "If-Modified-Since: ${__headers__[23]}"} \
375 | ${__headers__[24]:+-H "If-None-Match: ${__headers__[24]}"} \
376 | ${__headers__[25]:+-H "If-Range: ${__headers__[25]}"} \
377 | ${__headers__[26]:+-H "If-Unmodified-Since: ${__headers__[26]}"} \
378 | ${__headers__[27]:+-H "Max-Forwards: ${__headers__[27]}"} \
379 | ${__headers__[28]:+-H "Origin: ${__headers__[28]}"} \
380 | ${__headers__[29]:+-H "Pragma: ${__headers__[29]}"} \
381 | ${__headers__[30]:+-H "Proxy-Authorization: ${__headers__[30]}"} \
382 | ${__headers__[31]:+-H "Range: ${__headers__[31]}"} \
383 | ${__headers__[32]:+-H "Referer: ${__headers__[32]}"} \
384 | ${__headers__[33]:+-H "TE: ${__headers__[33]}"} \
385 | ${__headers__[34]:+-H "User-Agent: ${__headers__[34]}"} \
386 | ${__headers__[35]:+-H "Upgrade: ${__headers__[35]}"} \
387 | ${__headers__[36]:+-H "Via: ${__headers__[36]}"} \
388 | ${__headers__[37]:+-H "Warning: ${__headers__[37]}"} \
389 | --output $__bodyfile__ 2>&1
390 | )
391 |
392 | # Conteúdo
393 | __ref__[body]=$(< $__bodyfile__)
394 |
395 | return $?
396 | }
397 |
398 | # .FUNCTION http.connection() -> [bool]
399 | #
400 | # Define as configurações de conexão para o objeto apontado por 'conn'.
401 | #
402 | function http.connection()
403 | {
404 | getopt.parse 6 "conn:http_request_t:$1" "method:str:$2" "url:str:$3" "fields:map:$4" "headers:http_header_st:$5" "response:map:$6" "${@:7}"
405 |
406 | printf -v $1 '%s|%s|%s|%s|%s' "$2" "$3" "$4" "$5" "$6"
407 | return $?
408 | }
409 |
410 | # .FUNCTION http.conn_request -> [bool]
411 | #
412 | # Executa a conexão de requisição do objeto.
413 | #
414 | function http.conn_request()
415 | {
416 | getopt.parse 1 "conn:http_request_t:$1" "${@:2}"
417 |
418 | local __opts__
419 |
420 | IFS='|' read -a __opts__ <<< "${!1}"
421 | http.request "${__opts__[@]}"
422 |
423 | return $?
424 | }
425 |
426 | # .FUNCTION http.connection_data -> [bool]
427 | #
428 | # Como 'http.connection', porém para estrutura de dados.
429 | #
430 | function http.connection_data()
431 | {
432 | getopt.parse 6 "conn:http_requests_t:$1" "method:str:$2" "url:str:$3" "data:str:$4" "headers:http_header_st:$5" "response:map:$6" "${@:7}"
433 |
434 | printf -v $1 '%s|%s|%s|%s|%s' "$2" "$3" "$5" "$6" "$4"
435 | return $?
436 | }
437 |
438 | # .FUNCTION http.conn_request_data -> [bool]
439 | #
440 | # Executa a conexão de requisição do objeto.
441 | #
442 | function http.conn_request_data()
443 | {
444 | getopt.parse 1 "conn:http_requests_t:$1" "${@:2}"
445 |
446 | local __opts__
447 |
448 | IFS='|' read -ra __opts__ <<< "${!1}"
449 |
450 | http.request_data "${__opts__[0]}" \
451 | "${__opts__[1]}" \
452 | "${__opts__[4]}" \
453 | "${__opts__[2]}" \
454 | "${__opts__[3]}"
455 |
456 | return $?
457 | }
458 |
459 | # .FUNCTION http.conn_data -> [bool]
460 | #
461 | # Define a estrutura de dados do objeto.
462 | #
463 | function http.conn_data()
464 | {
465 | getopt.parse 2 "conn:http_requests_t:$1" "data:str:$2" "${@:3}"
466 |
467 | local __opts__
468 |
469 | IFS='|' read -ra __opts__ <<< "${!1}"
470 | printf -v $1 '%s|%s|%s|%s|%s' "${__opts__[@]:0:4}" "$2"
471 |
472 | return $?
473 | }
474 |
475 | # Estruturas
476 | var http_header_st struct_t
477 |
478 | # .STRUCT http_header_st
479 | #
480 | # Implementa o objeto 'S' com os membros:
481 | #
482 | # S.aim [str]
483 | # S.accept [str]
484 | # S.accept_charset [str]
485 | # S.accept_encoding [str]
486 | # S.accept_language [str]
487 | # S.accept_datetime [str]
488 | # S.accept_control_request_method [str]
489 | # S.accept_control_request_headers [str]
490 | # S.authorization [str]
491 | # S.cache_control [str]
492 | # S.connection [str]
493 | # S.content_length [uint]
494 | # S.content_md5 [str]
495 | # S.content_type [str]
496 | # S.cookie [str]
497 | # S.date [str]
498 | # S.expect [str]
499 | # S.forwarded [str]
500 | # S.from [str]
501 | # S.host [str]
502 | # S.http2_settings [str]
503 | # S.if_match [str]
504 | # S.if_modified_since [str]
505 | # S.if_none_match [str]
506 | # S.if_range [str]
507 | # S.if_unmodified_since [str]
508 | # S.max_forwards [uint]
509 | # S.origin [str]
510 | # S.pragma [str]
511 | # S.proxy_authorization [str]
512 | # S.range [str]
513 | # S.referer [str]
514 | # S.te [str]
515 | # S.user_agent [str]
516 | # S.upgrade [str]
517 | # S.via [str]
518 | # S.warning [str]
519 | #
520 | http_header_st.__add__ aim str \
521 | accept str \
522 | accept_charset str \
523 | accept_encoding str \
524 | accept_language str \
525 | accept_datetime str \
526 | accept_control_request_method str \
527 | accept_control_request_headers str \
528 | authorization str \
529 | cache_control str \
530 | connection str \
531 | content_length uint \
532 | content_md5 str \
533 | content_type str \
534 | cookie str \
535 | date str \
536 | expect str \
537 | forwarded str \
538 | from str \
539 | host str \
540 | http2_settings str \
541 | if_match str \
542 | if_modified_since str \
543 | if_none_match str \
544 | if_range str \
545 | if_unmodified_since str \
546 | max_forwards uint \
547 | origin str \
548 | pragma str \
549 | proxy_authorization str \
550 | range str \
551 | referer str \
552 | te str \
553 | user_agent str \
554 | upgrade str \
555 | via str \
556 | warning str
557 |
558 | # .MAP response
559 | #
560 | # Chaves:
561 | #
562 | # access-control-allow-origin
563 | # access-control-allow-credentials
564 | # access-control-expose-headers
565 | # access-control-max-age
566 | # access-control-allow-methods
567 | # access-control-allow-headers
568 | # accept-patch
569 | # accept-ranges
570 | # age
571 | # allow
572 | # alt-svc
573 | # cache-control
574 | # connection
575 | # content-disposition
576 | # content-encoding
577 | # content-language
578 | # content-length
579 | # content-location
580 | # content-md5
581 | # content-range
582 | # content-type
583 | # date
584 | # delta-base
585 | # etag
586 | # expires
587 | # im
588 | # last-modified
589 | # link
590 | # location
591 | # p3p
592 | # pragma
593 | # proxy-authenticate
594 | # public-key-pins
595 | # retry-after
596 | # server
597 | # set-cookie
598 | # strict-transport-security
599 | # trailer
600 | # transfer-encoding
601 | # tk
602 | # upgrade
603 | # vary
604 | # via
605 | # warning
606 | # www-authenticate
607 | # x-frame-options
608 | # proto
609 | # status
610 | # body
611 | #
612 |
613 | # .TYPE http_request_t
614 | #
615 | # Implementa o objeto 'S' com o método:
616 | #
617 | # S.conn_request
618 | #
619 | typedef http_request_t http.conn_request
620 |
621 | # .TYPE http_requests_t
622 | #
623 | # Implementa o objeto 'S' com o métodos:
624 | #
625 | # S.conn_request_data
626 | # S.conn_data
627 | #
628 | typedef http_requests_t http.conn_request_data \
629 | http.conn_data
630 |
631 | # Funções (somente-leitura)
632 | readonly -f http.get \
633 | http.request \
634 | http.request_data \
635 | http.connection \
636 | http.conn_request \
637 | http.connection_data \
638 | http.conn_request_data \
639 | http.conn_data
640 |
641 | # /* __HTTP_SH__ */
642 |
--------------------------------------------------------------------------------
/src/json.sh:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 |
3 | # Copyright 2018 Juliano Santos [SHAMAN]
4 | #
5 | # This file is part of bashsrc.
6 | #
7 | # bashsrc is free software: you can redistribute it and/or modify
8 | # it under the terms of the GNU General Public License as published by
9 | # the Free Software Foundation, either version 3 of the License, or
10 | # (at your option) any later version.
11 | #
12 | # bashsrc is distributed in the hope that it will be useful,
13 | # but WITHOUT ANY WARRANTY; without even the implied warranty of
14 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 | # GNU General Public License for more details.
16 | #
17 | # You should have received a copy of the GNU General Public License
18 | # along with bashsrc. If not, see .
19 |
20 | [ -v __JSON_SH__ ] && return 0
21 |
22 | readonly __JSON_SH__=1
23 |
24 | source builtin.sh
25 | source setup.sh
26 |
27 | # Dependência.
28 | setup.package 'jq (>= 1.5)'
29 |
30 | # .FUNCTION json.load -> [bool]
31 | #
32 | # Converte o arquivo contendo um documento JSON em uma estrutura
33 | # de dados mapeada e salva no objeto apontado por 'obj'.
34 | #
35 | function json.load()
36 | {
37 | getopt.parse 2 "file:str:$1" "obj:map:$2" "${@:3}"
38 |
39 | if [ ! -f "$1" ]; then
40 | error.error "'$1' não é um arquivo regular"
41 | return $?
42 | elif [ ! -r "$1" ]; then
43 | error.error "'$1' não foi possível ler o arquivo"
44 | return $?
45 | fi
46 |
47 | json.__setmap__ file "$1" $2
48 |
49 | return $?
50 | }
51 |
52 | # .FUNCTION json.loads -> [bool]
53 | #
54 | # Converte a expressão JSON em uma estrutura de dados mapeada
55 | # e salva no objeto apontado por 'obj'.
56 | #
57 | # == EXEMPLO ==
58 | #
59 | # #!/bin/bash
60 | #
61 | # source json.sh
62 | # source map.sh
63 | #
64 | # # Inicializa o map.
65 | # declare -A dados=()
66 | #
67 | # # Implementa o tipo map.
68 | # var dados map_t
69 | #
70 | # # Processando/convertendo JSON
71 | # json.loads '{"autor":{"nome":"Juliano","sobrenome":"santos","idade":35,"pseudonimo":"SHAMAN"}}' dados
72 | #
73 | # Listando as chaves do mapa.
74 | # dados.keys
75 | #
76 | # echo ---
77 | #
78 | # # Acessando valores.
79 | # dados.get autor.nome
80 | # dados.get autor.pseudonimo
81 | # dados.get autor.idade
82 | #
83 | # == SAÍDA ==
84 | #
85 | # autor.nome
86 | # autor.pseudonimo
87 | # autor.sobrenome
88 | # autor.idade
89 | # ---
90 | # Juliano
91 | # SHAMAN
92 | # 35
93 | #
94 | function json.loads()
95 | {
96 | getopt.parse 2 "expr:str:$1" "obj:map:$2" "${@:3}"
97 | json.__setmap__ expr "$1" $2
98 | return $?
99 | }
100 |
101 | # json.__setmap____