如何 运行 sed 命令接收 sed 文件并输出 sql 文件

How to run a sed command to take in a sed file and output a sql file

更新问题:http://pastebin.com/SrVC8PvW

Sed 文件 — csv2sql.sed:

s|\([A-Z]*\),\([A-Z]*\),\([A-Za-z0-9’ ()\.\!-]*\),\([A-Za-z0-9’ ()\.\!-]*\),\([0-9]*\)|INSERT INTO `Schedule` (`ID`,`YEAR`,`NUMBER`,`TeamR1`,`TeamR2`, `TeamR3`, `TeamB1`, `TeamB2`, `TeamB3`) VALUES ('', '', '', '', '', '', '', '', '');|g

CSV 文件(部分):

1,2015,0,57,3310,3676,624,3802,3481

控制台错误:

sed: file csv2sql.sed line 1: invalid reference  on `s` command's RHS

我有一个名为 csv2sql.sed 的 SED 文件,它将接收一个 CSV 文件并将其输出为 SQL 语法。我想要 运行 脚本,并在同一文件夹中有一个名为 schedules.sql 的 new sql 文件。

如何解决我遇到的错误?

你可以运行这样

sed -f csv2sql.sed tes1.csv

CSV:

ABC,ABC,AbC9).,AbC9).,98

输出:

INSERT INTO `Schedule` (`F1`,`F2`,`F3`,`F4`,`F5`) VALUES ('ABC', 'ABC', 'AbC9).', 'AbC9).', '98');

csv2sql.sed 看起来像这样

s|\([A-Z]*\),\([A-Z]*\),\([A-Za-z0-9’ ()\.\!-]*\),\([A-Za-z0-9’ ()\.\!-]*\),\([0-9]*\)|INSERT INTO `Schedule` (`F1`,`F2`,`F3`,`F4`,`F5`) VALUES ('', '', '', '', '');|g

假设你的 sed 文件是正确的(我对此表示怀疑),那么你会 运行

sed -f csv2sql.sed xxx.dat > schedules.sql

其中 xxx.dat 是包含您的 csv 数据的文件。

Schedules.sql 将在您当前的工作目录中创建。

这本来是评论,但它太复杂了,无法再在评论中展示,所以它成为一个答案。

sed 脚本设置了 5 个捕获,然后尝试引用捕获 1-9。错误信息告诉你,你不能引用你没有捕捉到的东西。

原始 sed 脚本似乎是:

s|\([A-Z]*\),\([A-Z]*\),\([A-Za-z0-9' ()\.\!-]*\),\([A-Za-z0-9' ()\.\!-]*\),\([0-9]*\)|INSERT INTO `Schedule` (`ID`,`YEAR`,`NUMBER`,`TeamR1`,`TeamR2`, `TeamR3`, `TeamB1`, `TeamB2`, `TeamB3`) VALUES ('', '', '', '', '', '', '', '', '');|g

其中的 'matching' 部分是:

|\([A-Z]*\),\([A-Z]*\),\([A-Za-z0-9' ()\.\!-]*\),\([A-Za-z0-9' ()\.\!-]*\),\([0-9]*\)|
  ^          ^          ^                         ^                         ^
  1          2          3                         4                         5

样本数据似乎是由逗号分隔的 9 个整数。这似乎与所使用的列标题不太相似,但这可能是一个单独的讨论。如果 CSV 数据足够简单,字段中不包含逗号或单引号(在本例中),那么您可以更简单地处理它:

s|\([^,]*\),\([^,]*\),\([^,]*\),\([^,]*\),\([^,]*\),\([^,]*\),\([^,]*\),\([^,]*\),\([^,]*\)|INSERT … VALUES ('', '', '', '', '', '', '', '', '');|

如果您的 sed 版本支持 ERE(扩展正则表达式),您可以将其简化为:

s|([^,]*\),([^,]*\),([^,]*\),([^,]*\),([^,]*\),([^,]*\),([^,]*\),([^,]*\),([^,]*\)|INSERT … VALUES ('', '', '', '', '', '', '', '', '');|

您可能需要使用 -r (GNU sed) 或 -E (BSD sed) 来启用 ERE。

这可以解决 sed 脚本中的技术问题。这是一种处理数据的可怕方式。对于示例数据,您可以使用 awk 来处理以下行:

awk -F, 'BEGIN { i1 = "INSERT INTO `Schedule` (`ID`,`YEAR`,`NUMBER`"
                 i2 = ",`TeamR1`,`TeamR2`, `TeamR3`, `TeamB1`,"
                 i3 = "`TeamB2`, `TeamB3`) VALUES"
               }
         NF==9 {printf "%s%s%s('%s','%s','%s','%s','%s','%s','%s','%s','%s');\n",
                       i1, i2, i3, , , , , , , , ,  }
        '

awk 中还有许多其他方法可以处理此问题,包括循环等

如果你真的需要处理CSV数据,那就使用理解CSV数据的语言。例如,Perl 标准安装了 Text::CSV (but it usually has to be installed as an extra) and Python has its csv 模块。这些中的任何一个都会使其更易于管理。

我不会为此使用 sedcsv 标准库中的 csv 模块似乎很可能可以解析您的输入,而您的编码要少得多,而且比您要编写的任何内容都要健壮得多在 sed.

这是一个简单的程序,它将读取您所描述的 CSV 文件,假设您有一个 header 行匹配您的列名列表(按字面意思引用,因为您希望它出现在您的 SQL) 并将其写入您所描述的一系列 INSERT INTO 语句中:

#!python
# For Python version 2.x > 2.6
import csv, sys
form = 'INSERT INTO `Schedule` {0} VALUES ({1});\n'

if __name__ == '__main__':
    num_args = len(sys.argv[1:])
    if num_args < 1:
        print >> sys.stderr, "Must supply input filename"
        sys.exit(1)

    with open(sys.argv[1], 'r') as infile:
        reader = csv.reader(infile)
        header = next(reader)
        data = list()
        for row in reader:
            data.append(row)

    with open('./csvdata.sql', 'w') as outfile:
        for each in data:
            outfile.write(form.format(', '.join(header), ', '.join(each)))

只需做一些额外的工作,您就可以为输入和输出文件名添加对命令行参数的支持,并将其转变为通用实用程序,用于为任何具有适当 [=56 的 CSV 生成 SQL INSERT 语句=] 行(您可以在其中指定使用命令行选项插入的 table)。

稍加努力,您可以省略 header 并使用一些 Python 从数据库中动态提取列名列表(执行 SELECT * FROMsometableWHERE 1=0 通过任何 Python DBAPI driver 并读取结果集 objects .description 属性).

为了说明简单,我只将其分成两个单独的循环...将 outfile.write() 合并到第一个循环中以消除 data.append,您可以处理任意大的文件常量内存开销。

直接添加 SQL 处理并弄清楚如何使用 .executemany() 并且您可以一次性执行操作(CSV -> 您的 SQL RDBMS),无需中介.sql 文本文件。 (这样做你可能还必须在 CSV 读取循环中添加一些类型处理)。但是,这可能比单个 SQL INSERT 语句的文本文件更有效。 (例如,这些 Python DBAPI driver 的部分可能在平台本机 C 二进制文件中,而不是通过 Python 为 .executemany() 中的每一行分派来执行)。

这是 Python 3.x 的脚本 suitable 的一个版本,并实现了稍微改进的参数处理。这里输出文件是第一个参数,所有其他参数都是输入文件:

#!python
#!/usr/bin/env python3
## Python 3.x
import csv, sys

usage='%s outfile infile [infile2 ...]' % sys.argv[0]

form = 'INSERT INTO `Schedule` {0} VALUES ({1});\n'

if __name__ == '__main__':
    num_args = len(sys.argv[1:])
    if num_args < 1:
        print ("Must supply input filename", file=sys.stderr)
        sys.exit(1)

    data = list()
    for each in sys.argv[2:]:
        try:
            with open(each, 'r') as infile:
                reader = csv.reader(infile)
                header = next(reader)
                for row in reader:
                    data.append(row)
        except EnvironmentError as e:
            print('Warning %s: unable to read data from %s' % (e, each), file=sys.stderr)

    try:
        with open(sys.argv[1], 'w') as outfile:
            for each in data:
                outfile.

write(form.format(', '.join(header), ', '.join(each))) 除了 EnvironmentError 为 e: 打印('Error: %s: unable to write results to %s' % (e, sys.argv[1], 文件=sys.stderr) sys.exit(1)

此版本还在文件 I/O 周围添加了非常简单的异常处理,将输入错误读取为 "Warnings" 并将任何输出错误读取为错误。