What is the best practice for return many values from a bash function?
Example1:
Function-script:
function mysqlquery {
local dbserver='localhost'
local dbuser='user'
local dbpass='pass'
local db='mydb'
mysql -h "$dbserver" -u "$dbuser" -p "$dbpass" --skip-column-names --raw -e "$*" "$db"
if [ $? -ne 0 ]; then
return 1
fi
}
Source-script:
for XY in $(mysqlquery "select XY from ABC where DEF = 123" 2>/dev/null);do
dosomethingwith $XY
done
if mysqlquery "select XY from ABC where DEF = 123" 2>/dev/null; then
echo true
fi
Example2:
Function-script:
function mysqlquery {
local dbserver='localhost'
local dbuser='user'
local dbpass='pass'
local db='mydb'
result=$(mysql -h "$dbserver" -u "$dbuser" -p "$dbpass" -e "$*" "$db" 2>/dev/null)
if [ $? -ne 0 -o -z "$result" ]; then
return 1
fi
}
Source-script:
result=$(mysqlquery "select XY from ABC where DEF = 123" 2>/dev/null)
for XY in $result;do
dosomethingwith $XY
done
if mysqlquery "select XY from ABC where DEF = 123" 2>/dev/null; then
echo true
fi
Or are there more approaches to returning multiple pieces of information (much more then a single int value)?
Best Answer
Yes,
bash
'sreturn
can only return numbers, and only integers between 0 and 255.For a shell that can return anything (lists of things), you can look at
es
:Now, in Korn-like shells like
bash
, you can always return the data in a pre-agreed variable. And that variable can be in any type supported by the shell.For
bash
, that can be scalar, sparse arrays (associative arrays with keys restricted to positive integers) or associative arrays with non-empty keys (neither key nor values can contain NUL characters).See also
zsh
with normal arrays and associative arrays without those restrictions.The equivalent of the
f
es
function above could be done with:Now,
mysql
queries generally return tables, that is two-dimensional arrays. The only shell that I know that has multi-dimensional arrays isksh93
(likebash
it doesn't support NUL characters in its variables though).ksh
also supports compound variables that would be handy to return tables with their headers.It also supports passing variables by reference.
So, there, you can do:
Or:
Now, to take the output of
mysql
and store that in some variables, we need to parse that output which is text with columns of the table separated by TAB characters and rows separated by NL and some encoding for the values to allow them to contain both NL and TAB.Without
--raw
,mysql
would output a NL as\n
, a TAB as\t
, a backslash as\\
and a NUL as\0
.ksh93
also hasread -C
that can read text formatted as a variable definition (not very different from usingeval
though), so you can do:To be used as
Or for a compound variable:
To be used as:
Note that the header names (
firstname
,lastname
above) have to be valid shell identifiers.In
bash
orzsh
oryash
(though beware array indices start at 1 in zsh and yash and onlyzsh
can store NUL characters), you could always return one array per column, by havingawk
generate the code to define them:To be used as:
Add a
set -o localoptions
withzsh
orlocal -
with bash4.4+ before theset -o pipefail
for the setting of that option to be local to the function like with theksh93
approach.Note that in all the above, we're not converting back the
\0
s to real NULs asbash
orksh93
would choke on them. You may want to do it if usingzsh
to be able to work with BLOBs but note that thegsub(/\\0/, "\0", s)
would not work with allawk
implementations.In any case, here, I'd use more advanced languages than a shell like perl or python to do this kind of thing.