将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所要求的。