Sim, bash return só pode retornar números e apenas inteiros entre 0 e 255.
Para um shell que pode retornar alguma coisa (listas de coisas), você pode ver es :
$ es -c "fn f {return (a 'b c' d \$*)}; printf '%s\n' <={f x y}"
a
b c
d
x
y
Agora, em shells semelhantes a Korn, como bash , você sempre pode retornar os dados em uma variável pré-acordada. E essa variável pode ser em qualquer tipo suportado pelo shell.
Para bash , isso pode ser matrizes escalares e esparsas (matrizes associativas com chaves restritas a inteiros positivos) ou matrizes associativas com chaves não vazias (nem chaves nem valores podem conter caracteres NUL).
Veja também zsh com matrizes normais e matrizes associativas sem essas restrições.
O equivalente da função f es acima pode ser feito com:
f() {
reply=(a 'b c' d "$@")
}
f
printf '%s\n' "${reply[@]}"
Agora, mysql consultas geralmente retornam tabelas, ou seja, matrizes bidimensionais. O único shell que eu sei que possui arrays multidimensionais é ksh93 (como bash ele não suporta caracteres NUL em suas variáveis).
ksh também suporta variáveis composto que seriam úteis para retornar tabelas com seus cabeçalhos.
Também suporta passar variáveis por referência.
Então, você pode fazer:
function f {
typeset -n var=$1
var=(
(foo bar baz)
(1 2 3)
}
}
f reply
printf '%s\n' "${reply[0][1]}" "${reply[1][2]}"
Ou:
function f {
typeset -n var=$1
var=(
(firstname=John lastname=Smith)
(firstname=Alice lastname=Doe)
)
}
f reply
printf '%s\n' "${reply[0].lastname}"
Agora, para obter a saída de mysql e armazenar isso em algumas variáveis, precisamos analisar essa saída que é texto com colunas da tabela separadas por caracteres e linhas TAB separados por NL e alguma codificação para os valores a serem permitir que eles contenham NL e TAB.
Sem --raw , mysql produziria um NL como \n , um TAB como \t , uma barra invertida como \ e um NUL como . ksh93
read -C também tem eval que pode ler texto formatado como uma definição de variável (não muito diferente de usar firstname ), então você pode fazer:
function mysql_to_narray {
awk -F '\t' -v q="'" '
function quote(s) {
gsub(/\n/, "\n", s)
gsub(/\t/, "\t", s)
gsub(/\\/, "\", s)
gsub(q, q "\" q q, s)
return q s q
}
BEGIN{print "("}
{
print "("
for (i = 1; i <= NF; i++)
print " " quote($i)
print ")"
}
END {print ")"}'
}
function query {
typeset -n var=$1
typeset db=$2
shift 2
typeset -i n=0
typeset IFS=' '
typeset credentials=/path/to/file.my # not password on the command line!
set -o pipefail
mysql --defaults-extra-file="$credentials" --batch \
--skip-column-names -e "$*" "$db" |
mysql_to_narray |
read -C var
}
Para ser usado como
query myvar mydb 'select * from mytable' || exit
printf '%s\n' "${myvar[0][0]}"...
Ou para uma variável composta:
function mysql_to_array_of_compounds {
awk -F '\t' -v q="'" '
function quote(s) {
gsub(/\n/, "\n", s)
gsub(/\t/, "\t", s)
gsub(/\\/, "\", s)
gsub(q, q "\" q q, s)
return q s q
}
BEGIN{print "("}
NR == 1 {
for (i = 1; i<= NF; i++) header[i] = $i
next
}
{
print "("
for (i = 1; i <= NF; i++)
print " " header[i] "=" quote($i)
print ")"
}
END {print ")"}'
}
function query {
typeset -n var=$1
typeset db=$2
shift 2
typeset -i n=0
typeset IFS=' '
typeset credentials=/path/to/file.my # not password on the command line!
set -o pipefail
mysql --defaults-extra-file="$credentials" --batch \
-e "$*" "$db" |
mysql_to_array_of_compounds |
read -C var
}
Para ser usado como:
query myvar mydb 'select "First Name" as firstname,
"Last Name" as lastname from mytable' || exit
printf '%s\n' "${myvar[0].firstname"
Observe que os nomes dos cabeçalhos ( lastname , bash acima) precisam ser identificadores de shell válidos.
Em zsh ou yash ou zsh (embora os índices das matrizes estejam em primeiro lugar em zsh e yash e somente awk pode armazenar caracteres NUL), você pode sempre retornar uma matriz por coluna, tendo set -o localoptions gera o código para defini-los:
query() {
typeset db="$1"
shift
typeset IFS=' '
typeset credentials=/path/to/file.my # not password on the command line!
set -o pipefail
typeset output
output=$(
mysql --defaults-extra-file="$credentials" --batch \
-e "$*" "$db" |
awk -F '\t' -v q="'" '
function quote(s) {
gsub(/\n/, "\n", s)
gsub(/\t/, "\t", s)
gsub(/\\/, "\", s)
gsub(q, q "\" q q, s)
return q s q
}
NR == 1 {
for (n = 1; n<= NF; n++) column[n] = $n "=("
next
}
{
for (i = 1; i < n; i++)
column[i] = column[i] " " quote($i)
}
END {
for (i = 1; i < n; i++)
print column[i] ") "
}'
) || return
eval "$output"
}
Para ser usado como:
query mydb 'select "First Name" as firstname,
"Last Name" as lastname from mytable' || exit
printf '%s\n' "${firstname[1]}"
Adicione um zsh com local - ou set -o pipefail com bash4.4 + antes do ksh93 para a configuração dessa opção ser local para a função, como com a abordagem . bash
Observe que, em todos os itens acima, não estamos convertendo de volta o ksh93 s para NULs reais, pois zsh ou gsub(/\0/, " se sufocariam neles. Você pode fazer isso usando %code% para poder trabalhar com BLOBs, mas observe que %code% não funcionaria com todas as implementações %code% . awk", s)
De qualquer forma, aqui, eu usaria linguagens mais avançadas do que um shell como perl ou python para fazer esse tipo de coisa.