将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“} }}”

逻辑解释什么是需要做的

  1. 首先,让我们看看RAW模式下的数据是怎样的 (使用--raw选项)。 数据库和表分别是tdump3

    您可以看到从“新行”(在第一行)开始的字段被分成三行,这是由于在行中放置了新行。

 mysql --skip-column-names --batch --raw -e'select * from dump3't

一行2个新行
引号“反斜杠\两个引号”“两个反斜杠\”两个制表符新行
场的结束

另一行1另一行描述没有任何特殊的字符
  1. 以批处理方式输出数据 (不带--raw选项) – 通过转义字符如\ <tab>new-lines每条logging改为单行文本
 mysql --skip-column-names --batch -e'select * from dump3't

一行2新行\ nquotation标记“反斜杠\\两个引号”“两个反斜杠\\\\\\\\\\\\\\\\\\\\\
另一行1另一行描述没有任何特殊的字符
  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所要求的。