1

現在、いくつかのhtmlデータがテキストファイルに保存されています。最近、フラットファイルではなくpgsqlデータベースにHTMLデータを保存することにしました。現在、「entries」テーブルには、ファイルを指す「path」列が含まれています。'path'が指すファイルにデータを保存する'content'列を追加しました。それが完了すると、「パス」列が削除されます。私が抱えている問題は、ファイルにアポストロフィが含まれているため、スクリプトがアポストロフィから外れることです。この問題を修正するにはどうすればよいですか?

これがスクリプトです

#!/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環境でサンプルファイル名を使用してこれをテストしました。

問題は、私がEditのcat $fアポストロフィを使用すると、 $ fの内容がSQL文字列を閉じ、構文エラーが発生することです。

4

2 に答える 2

2

一重引用符のエスケープの問題の場合、合理的な回避策は引用符を2倍にすることである可能性があるため、次を使用します。

`sed "s/'/''/g" < "$f"`

の代わりにファイルの内容を含めるには、ファイルを使用するつもりであると思われる場所でcatの2回目の呼び出しには、次を使用します。LIKE

${f/"'"/"''"/}

$fを実行する代わりにリテラル文字列の内容を含め、引用符を2倍にします。${varname/match/replace}式は構文であり、bashすべてのシェルで機能するとは限りません。使用する:

`echo "$f" | sed "s/'/''/g"`

他のシェルについて心配する必要がある場合。


そのSQLには他にもたくさんの問題があります。

  • 2回目の呼び出しで実行 しようとしています。$fあなたがそれを意図していなかったと私はかなり確信しています。リテラル文字列を含めるつもりだったと思います。
  • サブクエリも間違っています。括弧がありません。(SELECT ...)だけではありませんSELECT
  • あなたのLIKE表現もおそらくあなたが意図したことをしていないでしょう。SQLワイルドカードなので、おそらく%の代わりに意味します。*%

また、バッククォートを$()(IMOがより明確で読みやすいため)に変更し、サブクエリ構文を修正し、列を明確にするためにエイリアスを追加し、代わりにヒアドキュメントを使用してpsql's stdinに渡すと、結果は次のようになります。

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。そうでない場合は、正規表現を変更して、アポストロフィを2倍にするのではなく、アポストロフィをエスケープし\、文字列の前に。を付けるとE、にO'BrienなりE'O\'Brien'ます。最近のPostgreSQLでは、代わりにになり'O''Brien'ます。


一般に、データベースのスクリプトの問題を解決するには、DBD::Pgを使用したPerlやpsycopgを使用したPythonなどの実際のスクリプト言語を使用することをお勧めします。シェルでの作業は少しファンキーです。この式は、パラメーター化されたステートメントをサポートするデータベースインターフェイスを使用して作成する方がはるかに簡単です。

たとえば、私はこれを次のように書きます:

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ワイルドカード%はエスケープするために2倍になっているため%、最終的なSQLでは1になります。これは、Pythonが%フォーマット指定子として使用しているため、リテラル%をエスケープするには2倍にする必要があるためです。

上記のスクリプトを簡単に変更して、ファイル名のリストを受け入れ、データベースに1回接続して、すべてのファイル名のリストをループすることができます。これは、特にすべてを1つのトランザクションで実行する場合は、はるかに高速になります。psqlスクリプトでそれを行うのは本当に苦痛です。ここに示すように、bashコプロセスを使用する必要があります...そしてそれは面倒な価値がありません。

于 2012-11-18T09:18:41.890 に答える
0

元の投稿では、$fで表されるファイル名にアポストロフィがあるように聞こえるようにしました。これはそうではなかったので、簡単echo "$f"に私の問題を解決することができました。

より明確にするために、私のファイルの内容はhtmlスニペット(通常は。のようなもの)としてフォーマットされまし<p>Blah blah <b>blah</b>...</p>た。Craigによって投稿された解決策を試した後、いくつかのアンカータグで一重引用符を使用していたことに気付き、それらを別のものに変更したくありませんでした。この違反が発生したファイルはわずかしかなかったので、これらを手動で二重引用符に変更しました。また、アポストロフィをエスケープするのではなく、次のように変換する方がよいことにも気付きました。これ&apos;が、最終的に使用した最終的なスクリプトです。

dbname="myDB"
username="username"
fileroot="/path/to/files/*"

for f in $fileroot
do
psql $dbname $username << __END__
  UPDATE entries
  SET content='$(sed "s/'/\&apos;/g" < "$f")'
  WHERE id=(SELECT e.id FROM entries e WHERE path LIKE '%$(echo "$f")');
__END__
done

ここでのフォーマットの色付けは、構文が正しくないように見えるかもしれませんが、投稿されたとおりに正しいことを確認しました。

于 2012-11-18T22:27:47.077 に答える