从 bash 函数返回多个值的最佳做法是什么?
示例 1:
功能脚本:
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
}
源脚本:
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
示例 2:
功能脚本:
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
}
源脚本:
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
还是有更多方法可以返回多条信息(远不止一个 int 值)?
是的,
bash
'sreturn
只能返回数字,并且只能返回 0 到 255 之间的整数。对于可以返回任何内容(事物列表)的 shell,您可以查看
es
:现在,在类似 Korn 的 shell 中
bash
,您始终可以在预先约定的变量中返回数据。并且该变量可以是 shell 支持的任何类型。对于
bash
,可以是标量、稀疏数组(键限制为正整数的关联数组)或具有非空键的关联数组(键和值都不能包含 NUL 字符)。另请参阅
zsh
没有这些限制的普通数组和关联数组。上述功能的等价物
f
es
可以通过以下方式完成:现在,
mysql
查询通常返回表,即二维数组。我知道的唯一具有多维数组的外壳是ksh93
(bash
尽管它不支持其变量中的 NUL 字符)。ksh
还支持可以方便地返回带有标题的表的复合变量。它还支持通过引用传递变量。
所以,在那里,你可以这样做:
或者:
现在,为了获取一些变量的输出
mysql
并将其存储在某些变量中,我们需要解析该输出,该输出是文本,表的列由 TAB 字符分隔,行由 NL 分隔,并且对值进行了一些编码以允许它们同时包含 NL和标签。没有
--raw
,mysql
将输出 NL as\n
, TAB as\t
,反斜杠 as\\
和 NUL as\0
。ksh93
也read -C
可以读取格式化为变量定义的文本(虽然与使用没有太大不同eval
),所以你可以这样做:用作
或者对于复合变量:
用作:
请注意,标头名称(
firstname
以上lastname
)必须是有效的外壳标识符。在
bash
orzsh
oryash
中(尽管注意数组索引在 zsh 和 yash 中从 1 开始,并且只能zsh
存储 NUL 字符),您总是可以通过awk
生成代码来定义它们,每列返回一个数组:用作:
在 bash4.4+ 之前添加一个
set -o localoptions
withzsh
或local -
with bash4.4+,set -o pipefail
以便将该选项的设置设置为函数的本地,就像使用该ksh93
方法一样。请注意,在上述所有内容中,我们不会将
\0
s 转换回真正的 NUL,因为bash
或者ksh93
会阻塞它们。zsh
如果使用能够与 BLOB 一起工作,您可能想要这样做,但请注意,gsub(/\\0/, "\0", s)
这不适用于所有awk
实现。无论如何,在这里,我会使用比 perl 或 python 之类的 shell 更高级的语言来做这种事情。
好吧,这取决于您想要/需要什么样的输出格式。最简单的方法可能是只打印函数的输出,这样函数的行为就像任何其他命令一样。另一种方法是从函数内部设置一些变量(可能是关联数组)。这样做的好处是不同的项目被干净地分开,但您可能需要对一些变量进行硬编码。
您的第一个示例中的函数实现了前者:mysql 客户端从函数打印的任何内容都会转到函数的标准输出。鉴于数据已经以字节流的形式出现,保持原样就可以了。
虽然在这里,问题变成了如何处理输出。
for x in $(somecmd) ...
不好,因为 的输出somecmd
被拆分为单词并针对文件名 glob 进行处理。通常使用更好while read ...
,请参阅如何逐行(和/或逐字段)读取文件(数据流、变量)?mysql
要逐行读取输出,您可以执行或具有功能
请注意,您不需要
if [ $? -ne 0 ]; then return 1
: 函数的返回值与最后一个命令的返回值相同。如果您使用该函数来馈送管道,那么查看返回值并不容易。