如何将MySQL CLI查询输出转换为CSV

如何将MySQL CLI查询输出转换为CSV,mysql,sql,csv,sed,converter,Mysql,Sql,Csv,Sed,Converter,世界另一端的一位同事以文本格式向我发送了MySQL CLI客户端查询的一些输出。她不能为我将其转换为CSV,也不能使用到OUTFILE输出标志直接输出到CSV。如何将其转换为CSV格式?看起来是这样的: +-------------+------------------+------------------------------------------+-------------+ | pet_id | pet_identity_id | identity_value

世界另一端的一位同事以文本格式向我发送了MySQL CLI客户端查询的一些输出。她不能为我将其转换为CSV,也不能使用
到OUTFILE
输出标志直接输出到CSV。如何将其转换为CSV格式?看起来是这样的:

+-------------+------------------+------------------------------------------+-------------+
| pet_id      | pet_identity_id  | identity_value                           | pet_species |
+-------------+------------------+------------------------------------------+-------------+
|       77626 |          3140819 | dominic_dog@example.com                  | dog         |
|       77625 |          3140818 | missy_miauw@example.com                  | cat         |
|       77622 |          3140815 | shelly@example.com                       | aardvark    |
|       77583 |          3140776 | monster_moo@example.com                  | cow         |
+-------------+------------------+------------------------------------------+-------------+
4 rows in set (0.01 sec)
我希望它看起来像这个CSV格式(以管道或逗号分隔):


我发现了各种各样的问题,可以让您在CLI客户端中使用
转换为OUTFILE
符号来实现这一点,但仅仅是将某人以您在MySQL客户端屏幕上看到的形式发送给您的查询示例进行转换是不可能的。

下面是一个使用sed的小shell脚本,它可以做到这一点:

#!/bin/bash
# A script to convert MySQL CLI output to CSV format

# cat the file and pipe to the next step
cat $1 | \
# grep only the lines with '|' in them
grep "\|" | \
# Remove the lines which begin with '+'
sed -e '/^+/d' | \
# Remove the whitespace around the '|' characters
sed -e 's/[[:space:]]*|[[:space:]]*/|/g' | \
# Put a double quote before every '|' character
sed -e 's/|\(.\{1\}\)/\"&/g' | \
# Put a double quote after every '|' character
sed -e 's/\(.\{1\}\)|/&\"/g' | \
# Remove the extra '"|' from the beginning of each line
sed -e 's/^\"|//g' | \
# Remove the extra '"' from the end of each line
sed -e 's/\"$//g' | \
# Remove the '|' from the end of each line
sed -e 's/|$/\"/g' | \
# Remove the quotes from any purely numeric fields
sed -e 's/"\([[:digit:]]*\)"/\1/g'
只需将文件保存为例如convert-mysql.sh,然后将mysql输出复制并粘贴到文本文件mysql-output.txt中,然后运行例如:

$bash./convert-mysql.sh mysql output.txt

这将为您提供以下输出:

"pet_id"|"pet_identity_id"|"identity_value"|"pet_species"
77626|3140819|"dominic_dog@example.com"|"dog"
77625|3140818|"missy_miauw@example.com"|"cat"
77622|3140815|"shelly@example.com"|"aardvark"
77583|3140776|"monster_moo@example.com"|"cow"

这可以在Mac上运行,尽管在不同的Linux版本上sed可能略有不同,例如上面我的shell脚本中的
[[:digit:][]*
在我找到的一些示例中是
[[:digit:][]+

据我所知,您正在寻找某种方法将MySQL输出的“框架”表转换为CSV。下面是我自己的小Lua脚本(),它也根据RFC4180进行适当的内部引号转义:

local tabs,counter                      --to keep track of column markers
for line in io.lines(arg[1]) do
  if line:match '^%+[+-]+%+$' then      --frame line
    tabs = {}
    counter = 0
    for ch in line:gmatch '.' do
      counter = counter + 1
      if ch == '+' then tabs[#tabs+1] = counter end
    end
  elseif line:sub(1,1) == '|' then      --data line
    for _,tab in ipairs(tabs) do
      line = line:sub(1,tab-1) .. '\0' .. line:sub(tab+1)
    end
    line = line:gsub('%Z+',
      function(s)
        s = s:gsub('^%s*(.-)%s*$','%1')       --remove leading & trailing spaces (optional)
        if s ~= '' and not s:match '^-?%d-%.?%d+$' then
          s = '"' .. s:gsub('"','""') .. '"'  --add quotes while escaping internal ones
        end
        return s
      end)
    line = line:gsub('%z','|')
    print(line:sub(2,-2))
  end
end
它应该处理除多行字段之外的所有内容。 您可以通过文件名作为第一个参数或通过标准输入/管道将要处理的文件提供给它


编辑:正确处理嵌入的|(管道)字符的改进版本。

Thank@Nic3500的可能重复我编辑了这个问题,以更好地解释这适用于您自己无法访问CLI的输出-在这种情况下,有人发送了您(或您在线找到)从CLI剪切和粘贴示例输出。这里还有另一个类似的方法
local tabs,counter                      --to keep track of column markers
for line in io.lines(arg[1]) do
  if line:match '^%+[+-]+%+$' then      --frame line
    tabs = {}
    counter = 0
    for ch in line:gmatch '.' do
      counter = counter + 1
      if ch == '+' then tabs[#tabs+1] = counter end
    end
  elseif line:sub(1,1) == '|' then      --data line
    for _,tab in ipairs(tabs) do
      line = line:sub(1,tab-1) .. '\0' .. line:sub(tab+1)
    end
    line = line:gsub('%Z+',
      function(s)
        s = s:gsub('^%s*(.-)%s*$','%1')       --remove leading & trailing spaces (optional)
        if s ~= '' and not s:match '^-?%d-%.?%d+$' then
          s = '"' .. s:gsub('"','""') .. '"'  --add quotes while escaping internal ones
        end
        return s
      end)
    line = line:gsub('%z','|')
    print(line:sub(2,-2))
  end
end