通过 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 工具链的其余部分,例如 cut
和 awk
以检索您需要的字段并使用 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 脚本的主要内容,如果未能解决你的问题,请参考以下文章