我现在有一些html数据存储在文本文件中。我最近决定将HTML数据存储在pgsql数据库中而不是平面文件中。现在,'entries'表包含一个指向文件的'path'列。我添加了一个'content'列,现在应该将数据存储在'path'指向的文件中。完成后,“路径”列将被删除。我遇到的问题是文件包含撇号,使我的脚本失败。我该怎么做才能纠正这个问题?
这是脚本
#!/bin/sh
dbname="myDB"
username="username"
fileroot="/path/to/the/files/*"
for f in $fileroot
do
psql $dbname $username -c "
UPDATE entries
SET content='`cat $f`'
WHERE id=SELECT id FROM entries WHERE path LIKE '*`$f`';"
done
注意:id=SELECT...FROM...WHERE path LIKE ""
中的逻辑不是问题。我在pgsql环境中使用示例文件名对此进行了测试。
问题是,当我cat $f
时,编辑中的任何撇号: $ f的内容会关闭SQL字符串,并且会出现语法错误。
答案 0 :(得分:2)
对于单引号转义问题,合理的解决方法可能是将引号加倍,因此您可以使用:
`sed "s/'/''/g" < "$f"`
包含文件内容而不是cat
,以及LIKE
中您打算使用文件 name <的第二次调用/ em>使用:
${f/"'"/"''"/}
包含$f
的文字字符串内容而不是执行它,并将引号加倍。 ${varname/match/replace}
表达式是bash
语法,可能不适用于所有shell;使用方法:
`echo "$f" | sed "s/'/''/g"`
如果您需要担心其他炮弹。
SQL中存在许多其他问题。
$f
。我很确定你不是故意的;我想你想要包含文字字符串。 (SELECT ...)
不只是SELECT
。 LIKE
表达也可能没有按照你的意图行事;你可能意味着%
而不是*
,因为%
是SQL通配符。如果我也将反引号更改为$()
(因为它更清晰,更容易阅读IMO),修复子查询语法并添加别名以消除列的歧义,并使用here-document代替传递给{{1 stdin,结果是:
psql
以上假设您正在使用具有psql $dbname $username <<__END__
UPDATE entries
SET content=$(sed "s/'/''/g" < "$f")
WHERE id=(SELECT e.id FROM entries e WHERE e.path LIKE '$(echo "$f" | sed "s/'/''/g")');
__END__
的相当现代的PostgreSQL。如果不是,请将正则表达式更改为使用standard_conforming_strings = on
转义撇号而不是将它们加倍,并在字符串前加\
,因此E
变为O'Brien
。在现代的PostgreSQL中,它变成了E'O\'Brien'
。
一般来说,我建议使用像Perl这样的真实脚本语言,使用DBD :: Pg或Python和psycopg来解决数据库的脚本问题。使用shell有点时髦。使用支持参数化语句的数据库接口编写此表达式会更容易。
例如,我写如下:
'O''Brien'
请注意,SQL通配符import os
import sys
import psycopg2
try:
connstr = sys.argv[1]
filename = sys.argv[2]
except IndexError as ex:
print("Usage: %s connect_string filename" % sys.argv[0])
print("Eg: %s \"dbname=test user=fred\" \"some_file\"" % sys.argv[0])
sys.exit(1)
def load_file(connstr,filename):
conn = psycopg2.connect(connstr)
curs = conn.cursor()
curs.execute("""
UPDATE entries
SET content = %s
WHERE id = (SELECT e.id FROM entries e WHERE e.path LIKE '%%'||%s);
""", (filename, open(filename,"rb").read()))
curs.close()
if __name__ == '__main__':
load_file(connstr,filename)
加倍以使其转义,因此在最终SQL中会产生一个%
。这是因为Python使用%
作为其格式说明符,因此文字%
必须加倍才能使其转义。
您可以简单地修改上面的脚本以接受文件名列表,连接到数据库一次,并循环遍历所有文件名列表。那将是 lot 更快,特别是如果你在一个交易中完成所有这些。使用%
脚本执行此操作真的很痛苦;你必须使用bash协同进程as shown here ......这不值得麻烦。
答案 1 :(得分:0)
在原帖中,我听起来好像$ f表示的文件名中有撇号。事实并非如此,所以一个简单的echo "$f"
能够解决我的问题。
为了更清楚,我的文件内容被格式化为html片段,通常类似于<p>Blah blah <b>blah</b>...</p>
。在尝试了Craig发布的解决方案后,我意识到我在一些锚标签中使用了单引号,我不想将其更改为其他内容。只有少数文件发生了这种违规行为,所以我只是手动将这些文件更改为双引号。我也意识到,不是转义撇号,最好将它们转换为'
这是我最终使用的最终脚本:
dbname="myDB"
username="username"
fileroot="/path/to/files/*"
for f in $fileroot
do
psql $dbname $username << __END__
UPDATE entries
SET content='$(sed "s/'/\'/g" < "$f")'
WHERE id=(SELECT e.id FROM entries e WHERE path LIKE '%$(echo "$f")');
__END__
done
这里的格式着色可能会使它看起来像语法不正确,但我已经确认它是正确的发布。