通过 MySQL 循环的 Bash 脚本

Posted

技术标签:

【中文标题】通过 MySQL 循环的 Bash 脚本【英文标题】:Bash Script Loop Through MySQL 【发布时间】:2011-08-20 13:53:51 【问题描述】:

我需要一个可以从远程数据库检索 mysql 数据的 bash 脚本。实际上我已经完成了,但我现在需要它以某种方式循环记录并将变量传递给另一个 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。提前致谢。

【问题讨论】:

您是否有某些特定原因要避免使用脚本语言?您将无法在 bash 中正确解析 xml。您甚至可能在取消转义输出时遇到问题。为什么不使用简单的方法并使用 php / perl / python / lua / java / tcl / javascript / ... 或者除了 bash 之外的任何东西,它们根本无法为许多输出正确执行此操作? 不知道有没有办法输出为数组并循环遍历?我用谷歌搜索了这个可以我找不到任何东西。 【参考方案1】:

类似:

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: line 9: done' 实际上做错了,但后来我得到了一个不同的错误。它说 /winterboard_theme_builder/get_themes.sh: line 7: read: `theme_name,': not a valid identifier 哦,对了。 read 参数之间没有逗号,do 之前有一个分号。固定 我对这种方法有疑问。当您的循环结果中有列单元格有 2 个 word 时,命令将第一个变量的一部分分配给 1 ,将其他部分分配给 2 。假设如果 $theme_name="Theme Name" 和 $guid="12" 在 db 中,则此命令将回显 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 正如我在答案中所说,如果只有其中一列可以有空格,那就把它放在最后。 read 命令将所有“剩余”结果分配给最后一个变量。对于更复杂的事情,理论上你可以让它与精确的引用量一起工作;但最好使用真正的编码(XML、CSV、记录样式等),或任何其他不会尝试解析您处理的每个字符串的语言。【参考方案2】:

我建议您使用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 轻松配置我的输出。谢谢!【参考方案3】:

当输出中有空格时,接受的答案不起作用。这是一个简单的解决方法(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

当然,您会想要替换您自己的查询。

【讨论】:

【参考方案4】:

管道'|' to while 是危险的,因为循环内部的变化发生在另一个子进程中,不会在当前脚本中生效。

顺便说一句,我讨厌求助于外部文件解决方案。

我建议使用“Process Substitute”。

while read field1 field2 field3
do
done < <(mysql -NB -e "$sql")
#     ^
#   space needed

【讨论】:

这种情况下如何检测mysql查询/连接是否失败?

以上是关于通过 MySQL 循环的 Bash 脚本的主要内容,如果未能解决你的问题,请参考以下文章

While循环重置Bash脚本中的数字变量[重复]

如何在只有 1 个连接的 bash 循环中运行多个 sqlplus 查询

do 循环的 Bash 脚本,用于检测经过的时间段然后继续

玩转Bash脚本:循环结构之while循环(转)

12.3bash脚本循环语句

bash循环语句