Bash脚本循环遍历MySQL

18

我需要一个bash脚本,可以从远程数据库检索MySQL数据。实际上我已经做到了这一点,但现在我需要通过某种方式循环遍历记录,并将变量传递给另一个bash文件。 这是我的MySQL调用:

mysql -X -u $MyUSER -p$MyPASS -h$MyHOST -D$MyDB -e'SELECT `theme_name`, `guid` FROM `themes` WHERE `theme_purchased`="1" AND `theme_compiled`='0';' > themes.xml
download_themes.sh

目前它将数据导出到名为theme.xml的xml文件中,我只是想找出一些通过数据进行循环的方法。我正在尝试避免使用PHP和perl,只想使用bash。提前感谢。


4
你是否有避免使用脚本语言的特定原因?在Bash中,你将无法正确解析XML。你甚至可能会在取消转义输出时遇到问题。为什么不采用简单的方法,使用PHP / Perl / Python / Lua / Java / Tcl / JavaScript等任何其他语言,而非Bash,这些语言可以更好地处理许多输出呢? - viraptor
你不知道是否有一种方法可以将输出作为数组并循环遍历吗?我已经在谷歌上搜索了,但没有找到任何相关的信息。 - Brian Leishman
4个回答

52

something like:

mysql -e "SELECT `theme_name`, `guid` FROM `themes` WHERE `theme_purchased`='1' AND `theme_compiled`='0'" | while read theme_name guid; do
    # use $theme_name and $guid variables
    echo "theme: $theme_name, guid: $guid"
done

简而言之:当输出为管道时,mysql命令输出以'\n'分隔的记录和以'\t'分隔的字段。read命令读取一行,将其分割成字段,并将每个字段放入一个变量中。
如果数据的字段中有空格,则默认的read分割会导致一些问题。有一些解决方法;但是,如果您只需要读取两个字段,并且其中一个字段不应该包含任何空格(例如guid),那么您可以将“危险”的字段放在最后,read将把所有“额外”的内容放入最后一个变量中。
像这样:
mysql -e "SELECT `guid` `theme_name`, FROM `themes` WHERE `theme_purchased`='1' AND `theme_compiled`='0'" | while read guid theme_name; do
    # use $theme_name and $guid variables
    echo "theme: $theme_name, guid: $guid"
done

第一次似乎可以工作,但现在它给了我这个: /winterboard_theme_builder/get_themes.sh: 第9行:附近没有预期的标记“done” /winterboard_theme_builder/get_themes.sh: 第9行:`done' - Brian Leishman
实际上,do关键字在错误的行上,但是接着我又遇到了不同的错误。它说/winterboard_theme_builder/get_themes.sh: 第7行: read: `theme_name,': 不是一个有效的标识符。 - Brian Leishman
1
我对这种方法有问题。当您在循环中拥有列单元格包含2个单词的结果时,那么该命令将第一个变量的一部分分配给1,另一部分分配给2。假设$theme_name="Theme Name"和$guid="12"在数据库中,则此命令将回显theme:Theme guid:Name 12。有什么线索如何解决???? 主题:LalaPala,guid:44.5,40.18,44.52,40.17 主题:San,guid:Francisco -122.58,37.81,-122.33,37.71 主题:Edirne,guid:26.51,41.69,26.64,41.64 - MR.GEWA
正如我在答案中所说的,如果只有一个列可以包含空格,就将其放在最后。read命令将所有“剩余”的结果分配给最后一个变量。对于任何更复杂的情况,理论上你可以通过确切的引用数量来使其工作,但最好使用真正的编码(XML、CSV、记录样式等)或任何其他不会尝试解析你处理的每个字符串的语言。 - Javier
你无法在那个循环内设置全局变量。 - davide
显示剩余2条评论

9
我建议您使用SELECT INTO OUTFILE语法或者mysql --batch --raw将数据输出为制表符分隔的值,而不是输出XML。这样您就可以更容易地通过bash访问Unix工具链的其他部分,例如cutawk来检索所需字段并在Bash中重复使用它们。无需其他脚本语言,也无需处理XML。
mysql --batch --raw -u $MyUSER -p$MyPASS -h$MyHOST -D$MyDB -e'SELECT `theme_name`, `guid` FROM `themes` WHERE `theme_purchased`="1" AND `theme_compiled`='0';' \
| awk '{print "theme: " $1  " guid: " $2}'

喜欢这个解决方案,我认为它应该是被接受的答案。更加简洁,没有循环,让我可以轻松地使用 awk print 配置我的输出。谢谢! - pgr

7

如果输出中有空格,接受的答案将无法使用。但它很容易修复(IFS=$'\t' -- 注意$符号 -- 这很奇怪):


>mysql ... -BNr -e "SELECT 'funny man', 'wonderful' UNION SELECT 'no_space', 'I love spaces';" | while IFS=$'\t' read theme_name guid; do echo "theme: $theme_name guid: $guid"; done
theme: funny man guid: wonderful
theme: no_space guid: I love spaces

当然,你需要替换成自己的查询。


2
将管道符 '|' 传输到 while 循环中是危险的,因为在循环内部的更改会发生在另一个子进程中,在当前脚本中不起作用。
顺便说一下,我不喜欢采用外部文件解决方案。
我建议使用“进程替代”。
while read field1 field2 field3
do
done < <(mysql -NB -e "$sql")
#     ^
#   space needed

如何检测MySQL查询/连接失败的情况? - Siva

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接