将MySQL命令行结果的输出格式更改为CSV
我想从查询的输出中获取无标题的CSV数据到命令行上的MySQL。 我在与MySQL服务器不同的机器上运行这个查询,因此所有那些用“INTO OUTFILE”回答的问题都不好。
所以我运行mysql -e "select people, places from things" 。 输出的东西看起来有点像这样:
+--------+-------------+ | people | places | +--------+-------------+ | Bill | Raleigh, NC | +--------+-------------+
那么,这是不好的。 但是,嘿,看! 如果我把它pipe到任何东西 ,它把它变成一个制表符分隔列表:
people places Bill Raleigh, NC
这是更好的 – 至less它是以编程方式parsing。 但是我不想要TSV,我想要CSV,而且我不需要这个头文件。 我可以用mysql <stuff> | tail -n +2去掉头文件 mysql <stuff> | tail -n +2 ,但这是一个麻烦,如果MySQL只是有一个标志忽略它,我想避免。 而且我不能用逗号replace所有的选项卡,因为它不能用逗号来处理内容。
那么,我怎样才能让MySQL省略标题并以CSV格式给我提供数据呢?
作为一个部分的答案: mysql -N -B -e "select people, places from things"
-N告诉它不要打印列标题。 -B是“批处理模式”,并使用制表符分隔字段。
如果制表符分隔值不够,请参阅此Stackoverflow问答 。
我结束了写我自己的命令行工具来照顾这一点。 它与cut相似,只是它知道如何处理带引号的字段等。这个工具与@Jimothy的答案配合,允许我从远程MySQL服务器获取无标题CSV,我没有文件系统访问到我的本地机器上命令:
$ mysql -N -e "select people, places from things" | csvm -i '\t' -o ',' Bill,"Raleigh, NC"
github上的csvmaster
如何在客户端将结果保存为CSV,而无需额外的非标准工具。 这个例子只使用 mysql客户端和awk 。
一条线:
mysql --skip-column-names --batch -e'select * from dump3't | awk -F'\ t''{sep =“”; 对于(i = 1; i <= NF; i ++){gsub(/ \\ t /,“\ t”,$ i); GSUB(/ \\ N /, “\ n”,$ⅰ); GSUB(/ \\\\ /, “\\”,$ⅰ); gsub(/“/”,“\”“,$ i); printf sep”\“”$ i“\”“; sep =”,“; if(i == NF){printf”\ n“} }}”
逻辑解释什么是需要做的
-
首先,让我们看看RAW模式下的数据是怎样的 (使用
--raw选项)。 数据库和表分别是t和dump3您可以看到从“新行”(在第一行)开始的字段被分成三行,这是由于在行中放置了新行。
mysql --skip-column-names --batch --raw -e'select * from dump3't 一行2个新行 引号“反斜杠\两个引号”“两个反斜杠\”两个制表符新行 场的结束 另一行1另一行描述没有任何特殊的字符
- 以批处理方式输出数据 (不带
--raw选项) – 通过转义字符如\<tab>和new-lines每条logging改为单行文本
mysql --skip-column-names --batch -e'select * from dump3't 一行2新行\ nquotation标记“反斜杠\\两个引号”“两个反斜杠\\\\\\\\\\\\\\\\\\\\\ 另一行1另一行描述没有任何特殊的字符
- 并以CSV格式输出数据
线索是使用转义字符以CSV格式保存数据。
要做到这一点的方法是将特定的实体,其中mysql --batch生产( \t为标签\\为背光和\\换行符)为每个值(字段)的等效字节。 然后整个价值被"封闭也"所逃脱。 顺便说一句 – 使用相同的字符转义和封闭轻轻地简化了输出和处理,因为你没有两个特殊字符。 由于这个原因,所有你需要做的值(从CSV格式的angular度来看)是改变"为"" whithin值。更常见的方式(转义和封闭分别\和" ),你将不得不首先改变\然后改成"成\" 。
和命令的解释一步一步 :
#我们产生单行输出,如步骤2所示。
mysql --skip-column-names --batch -e'select * from dump3't
#设置字段分隔符,因为mysql以这种方式生成
| awk -F'\ t'
#这个开始迭代每一行/logging从MySQL数据 - awk的标准行为
“{
#字段分隔符为空,因为我们不在第一个输出字段之前打印分隔符
九月= “”;
- 迭代每个字段并将字段转换为csv的适当值
for(i = 1; i <= NF; i ++){
- 注意:\\ awk下面的两个斜杠表示awk,因为它们被转义了
- 把\ t改成对应于<tab>的字节
gsub(/ \\ t /,“\ t”,$ i);
- 将\ n更改为对应于新行的字节
gsub(/ \\ n /,“\ n”,$ i);
- 把两个\\变成一个\
GSUB(/ \\\\ /, “\\”,$ⅰ);
- 从字面上将价值转化为CSV - 将“改为”“
gsub(/“/,”\“\”“,$ i);
- 打印输出字段“,并添加分隔符
printf sep“\”“$ i”\“”;
- 在第一个字段被处理后设置分隔符 - 因为之前我们不需要它
九月= “”;
- 处理最后一个字段后添加新行 - 这表示csvlogging分隔符
if(i == NF){printf“\ n”}
}
}”
mysqldump实用程序可以帮助你,基本上用--tab选项它是一个包装的SELECT INTO OUTFILE语句。
例:
mysqldump -u root -p --tab=/tmp world Country --fields-enclosed-by='"' --fields-terminated-by="," --lines-terminated-by="\n" --no-create-info
这将创buildcsv格式的文件/tmp/Country.txt
如何使用sed? 它是大多数(所有?)Linux操作系统的标准。
sed 's/\t/<your_field_delimiter>/g' 。
这个例子使用GNU sed(Linux)。 对于POSIX sed(AIX / Solaris),我相信你会input一个字面的TAB而不是\t
示例(对于CSV输出):
#mysql mysql -B -e "select * from user" | while read; do sed 's/\t/,/g'; done localhost,root,,Y,Y,Y,Y,Y,Y,Y,Y,Y,Y,Y,Y,Y,Y,Y,Y,Y,Y,Y,Y,Y,Y,Y,Y,Y,Y,Y,Y,Y,,,,,0,0,0,0,, localhost,bill,*2470C0C06DEE42FD1618BB99005ADCA2EC9D1E19,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,,,,,0,0,0,0,, 127.0.0.1,root,,Y,Y,Y,Y,Y,Y,Y,Y,Y,Y,Y,Y,Y,Y,Y,Y,Y,Y,Y,Y,Y,Y,Y,Y,Y,Y,Y,Y,Y,,,,,0,0,0,0,, ::1,root,,Y,Y,Y,Y,Y,Y,Y,Y,Y,Y,Y,Y,Y,Y,Y,Y,Y,Y,Y,Y,Y,Y,Y,Y,Y,Y,Y,Y,Y,,,,,0,0,0,0,, %,jim,*2470C0C06DEE42FD1618BB99005ADCA2EC9D1E19,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,,,,,0,0,0,0,,
上述解决scheme仅适用于特殊情况。 embedded的逗号,embedded的引号,以及在一般情况下使CSV变得困难的其他事情都会让你陷入各种麻烦。
帮你一个忙,使用一个通用的解决scheme – 做对,你永远不用再考虑了。 一个非常强大的解决scheme是csvkit命令行实用程序 – 可通过Python使用所有操作系统。 通过pip install csvkit 。 这会给你正确的CSV数据:
mysql -e "select people, places from things" | csvcut -t
这会产生逗号分隔的数据,并且头部仍然存在。 删除标题行:
mysql -e "select people, places from things" | csvcut -t | tail -n +2
这产生了OP所要求的。