Bash 语法错误:“(”在使用带有“e”标志的GNU sed时意外 期望的最终结果

Bash 语法错误:“(”在使用带有“e”标志的GNU sed时意外 期望的最终结果,bash,sed,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" 调用日期-d'.''+%s'将

我正在尝试转换以下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"
调用日期-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:语法错误:意外

根据我跟踪的情况,括号会导致行失败:

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

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

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

$  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 ...>

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

$  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 ...>
此带有ge标志的sed用于您的工作:

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

$ 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));
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,只需创建适当的组,我认为您可以管理它。

此带有ge标志的sed用于您的工作:

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

$ 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));
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,只需建立适当的组,我认为您可以管理它。

有趣的实现!但据我所知,它不处理多个日期位于同一行时的情况。@SlavaSemushin我认为这是可以做到的。如果我们只讨论可行性,我们可以嵌套sed/awk/grep/..在sed中。只是一个复杂的问题。但这可以由gnu sed完成。不过,echo$日期有点粗糙。如果匹配文本中没有百分比符号,则date-d\2+\1%s\3可能更容易刺激眼睛和神经。谢谢,@Kent!你的意思是进行全局匹配时需要表达式如中所示,对吗?@AlexGyoshev是的。你问了sed s/../../ge,所以我回答了。但是如果情况更复杂,那么perl/awk/script..可能比sed更好。有趣的实现!但据我所知,它不能处理多个日期位于同一行时的情况。@SlavaSemushin我认为这是可以做到的。如果我们只讨论可行性。we可以将sed/awk/grep/…嵌套在sed中。这只是一个复杂的问题。但可以由gnu-sed完成。不过,echo$日期有点麻烦。如果匹配的文本中没有百分号,则date-d\2+\1%s\3可能更容易刺激眼睛和神经。谢谢,@Kent!你的意思是说进行全局匹配需要表达式像sho一样吗wn in,对吗?@AlexGyoshev是的。你问了sed s/./../ge,所以我回答了。但是如果情况更复杂,那么perl/awk/script..可能比sed更好。感谢分享strace技术,调试非常方便。解决方案也很好,如果我没有错的话,如果有很多重复项,结合uniq可以使它更快。感谢您的帮助使用strace技术,调试非常方便。如果我没有错的话,解决方案也很好,如果有很多重复项,结合uniq可以使它更快。