语法错误:"("使用带有' e'标志的GNU sed时出现意外

时间:2014-10-24 10:21:53

标签: bash sed

期望的最终结果

我正在尝试转换以下(MS-SQL)字符串

INSERT INTO Foo (Bar) VALUES (CAST('1958-08-22 21:00:00.000' AS DateTime))

到SQLite语法

INSERT INTO Foo (Bar) VALUES (-358491600)

方法

我使用以下sed参数成功完成此操作:

sed -r "s#cast\('(.*)' as datetime\)#date -d '\1' '+%s'#ige"

(调用date -d '...' '+%s'将日期转换为纪元)

问题

在整行上运行相同的命令:

echo "INSERT INTO Foo (Bar) values (cast('1958-08-22 21:00:00.000' as datetime))" | \
    sed -r "s#cast\('(.*)' as datetime\)#date -d '\1' '+%s'#ige"

...产生错误:sh: 1: Syntax error: "(" unexpected

根据我追踪的情况,括号会导致线路失败:

echo "() cast('1958-08-22 21:00:00.000' as datetime)" | \
    sed -r "s#cast\('(.*)' as datetime\)#date -d '\1' '+%s'#ige"

正确删除e开关可转换命令。我做错了什么?

2 个答案:

答案 0 :(得分:2)

如果您在strace下运行命令以查看将执行哪些exacly,您将看到以下内容:

$  echo "INSERT INTO Foo (Bar) values (cast('1958-08-22 21:00:00.000' as datetime))" | strace -ff sed -r "s#cast\('(.*)' as datetime\)#date -d '\1' '+%s'#ige" 2>&1 | grep 'execve('
execve("/bin/sed", ["sed", "-r", "s#cast\\('(.*)' as datetime\\)#dat"...], [/* 27 vars */]) = 0
[pid  8179] execve("/bin/sh", ["sh", "-c", "INSERT INTO Foo (Bar) values (da"...], [/* 27 vars */] <unfinished ...>

这意味着sed不仅尝试执行与模式匹配的文本而且还尝试执行整行。所以,可能,你不能用sed执行此操作(我很高兴,如果我错了。)

所以,我建议从文件中收集所有日期,转换它们然后逐个替换。例如:

$ cat q.sql
INSERT INTO Foo (Bar) VALUES (CAST('1958-08-22 21:00:00.000' AS DateTime));
INSERT INTO Foo (Bar) VALUES (CAST('1958-08-23 22:00:00.000' AS DateTime));
$ sed "s|.*CAST('\([^']\+\)'.*|\1|" q.sql | while read DATE; do sed -i "s|$DATE|$(date -d "$DATE" '+%s')|" q.sql; done
$ cat q.sql
INSERT INTO Foo (Bar) VALUES (CAST('-358495200' AS DateTime));
INSERT INTO Foo (Bar) VALUES (CAST('-358405200' AS DateTime));

答案 1 :(得分:2)

带有ge标志的sed完成了您的工作:

sed -r 's/(.*CAST[^\x27]*\x27)([^\x27]*)(\x27 AS DateTime.*)/
      echo "\1"$(date -d"\2" "+%s")"\3"/ge' file

以你的例子:

kent$  cat f
INSERT INTO Foo (Bar) VALUES (CAST('1958-08-22 21:00:00.000' AS DateTime));
INSERT INTO Foo (Bar) VALUES (CAST('1958-08-23 22:00:00.000' AS DateTime));
kent$  sed -r 's/(.*CAST[^\x27]*\x27)([^\x27]*)(\x27 AS DateTime.*)/echo "\1"$(date -d"\2" "+%s")"\3"/ge' file
INSERT INTO Foo (Bar) VALUES (CAST('-358488000' AS DateTime));
INSERT INTO Foo (Bar) VALUES (CAST('-358398000' AS DateTime));

如果您不希望输出As DateTime,只需制作合适的群组,我认为您可以管理它。