シェルを使用してデータベースがPostgreSQLに存在するかどうかを確認します


130

PostgreSQLデータベースが存在するかどうかを確認するためにシェルを使用することが可能かどうかについて誰かが私に言うことができるかどうか疑問に思っていましたか?

私はシェルスクリプトを作成していて、データベースがまだ存在していない場合にのみデータベースを作成したいのですが、今までそれを実装する方法を確認できませんでした。

回答:


199

Arturoのソリューションの次の変更を使用します。

psql -lqt | cut -d \| -f 1 | grep -qw <db_name>


それがすること

psql -l 次のようなものを出力します:

                                        List of databases
     Name  |   Owner   | Encoding |  Collate   |   Ctype    |   Access privileges   
-----------+-----------+----------+------------+------------+-----------------------
 my_db     | my_user   | UTF8     | en_US.UTF8 | en_US.UTF8 | 
 postgres  | postgres  | LATIN1   | en_US      | en_US      | 
 template0 | postgres  | LATIN1   | en_US      | en_US      | =c/postgres          +
           |           |          |            |            | postgres=CTc/postgres
 template1 | postgres  | LATIN1   | en_US      | en_US      | =c/postgres          +
           |           |          |            |            | postgres=CTc/postgres
(4 rows)

素朴なアプローチを使用すると、「List」、「Access」、または「rows」というデータベースの検索が成功します。したがって、この出力を組み込みのコマンドラインツールの束にパイプして、最初の列のみを検索します。


-tフラグは、ヘッダとフッタを削除します。

 my_db     | my_user   | UTF8     | en_US.UTF8 | en_US.UTF8 | 
 postgres  | postgres  | LATIN1   | en_US      | en_US      | 
 template0 | postgres  | LATIN1   | en_US      | en_US      | =c/postgres          +
           |           |          |            |            | postgres=CTc/postgres
 template1 | postgres  | LATIN1   | en_US      | en_US      | =c/postgres          +
           |           |          |            |            | postgres=CTc/postgres

次のビットはcut -d \| -f 1、出力を垂直パイプ|文字(シェルからバックスラッシュでエスケープしたもの)で分割し、フィールド1を選択します。

 my_db             
 postgres          
 template0         

 template1         

grep -w単語全体に一致するためtemp、このシナリオで検索している場合は一致しません。この-qオプションは、画面に書き込まれる出力を抑制します。そのため、コマンドプロンプトでこれをインタラクティブに実行する場合は、除外して-q、何かがすぐに表示されるようにすることができます。

grep -w、英数字、数字、およびアンダースコアに一致することに注意してください。これは、postgresqlの引用符で囲まれていないデータベース名で許可されている文字のセットです(引用符で囲まれていない識別子ではハイフンは無効です)。他の文字を使用している場合は、grep -w機能しません。


このパイプライン全体の終了ステータスは0、データベースが存在する場合は(成功)、存在1しない場合は(失敗)になります。シェルは特殊変数$?を最後のコマンドの終了ステータスに設定します。条件で直接ステータスをテストすることもできます。

if psql -lqt | cut -d \| -f 1 | grep -qw <db_name>; then
    # database exists
    # $? is 0
else
    # ruh-roh
    # $? is 1
fi

8
追加... | grep 0して、DBが存在しない場合はシェルの戻り値を0、存在する場合は1にすることもできます。または... | grep 1逆の動作
acjay

2
@ acjohnson55はさらに良い:wc完全に削除します。私の改訂版をご覧ください。(あなたは終了ステータスを逆にしたい場合は、bashは強打演算子をサポートしています。! psql ...
benesch

ちょうど今これを見ている、素晴らしい
vol7ron

1
wcコマンドを削除する他の提案に加えて、私はを使用しますgrep -qw <term>。これにより、0一致するものがあればシェルが戻り1ます。次に、$?戻り値が含まれ、それを使用して次に何をするかを決定できます。したがって、wcこの場合は使用しないことをお勧めします。grepあなたが必要なことをします。
Matt Friedman

私はあなたのフィードバックに基づいてこの回答を更新することにしました。皆さんありがとう。
kibibu 2016年

81

次のシェルコードは私にはうまくいくようです:

if [ "$( psql -tAc "SELECT 1 FROM pg_database WHERE datname='DB_NAME'" )" = '1' ]
then
    echo "Database already exists"
else
    echo "Database does not exist"
fi

1
外部のカットgrep wcやその他のものをリレーしないのが好きです。dbの存在を確認します。これは、おそらく少なくともpsqlがあり、使用するコマンドが最小限で唯一であることを意味します。とても素敵です。主題の他に、シェルのタイプやコマンドのバージョンやディストリビューションについては触れていませんでした。私はそれを知るための他の回答で見たようなシステムツールにパイプのこのような大量のファイルをリレーすることはありません。それは何年も後の問題につながります
Riccardo Manfrin

1
@RiccardoManfrinに同意します。これはより直接的な解決策のようです。
トラビス

:あなたは非postgresユーザでこれを実行する必要がある場合はどれも、あなたが常に存在することにtemplate1データベースはpostgres使用することができます存在しない可能性があるので、あなたは、-Uユーザーを追加し、それに接続するデータベースを一覧表示することができます psql -U user -tAc "SELECT 1 FROM pg_database WHERE datname='DB_NAME'" template1
1月

cygwinでは、psqlは奇妙な制御文字を出力( '1 \ C-M')に追加し、出力が1のみで始まるかどうかを確認する必要がありますif [[ $(...) == 1* ]]
jan

28
postgres@desktop:~$ psql -l | grep <exact_dbname> | wc -l

指定したデータベースが存在する場合は1を返し、それ以外の場合は0を返します。

また、すでに存在するデータベースを作成しようとすると、postgresqlは次のようなエラーメッセージを返します。

postgres@desktop:~$ createdb template1
createdb: database creation failed: ERROR:  database "template1" already exists

10
最初の提案は非常に危険です。何が起こるexact_dbname_testでしょうか?テストの唯一の方法は、それに接続することです。
wildplasser 2013年

6
この答えは堅固ではありません!検索語句が別の列にある場合は、ゼロ以外の数値を出力します(戻されません!)。これを行うためのより正確な方法については、kibibuの回答を参照してください。
acjay 2013年

1
「foo-bar」という名前のデータベースが存在する場合、「grep -w foo」を使用すると誤検知が発生する可能性があります。言うまでもなく、psql出力ヘッダー内のすべての単語が検索されます。
Marius Gedminas 2013

1
私はこの答えに強く同意しません。この式を論理ステートメントで使用する場合は、常にtrueになります。これらの例をテストして試すことができます: psql -l | grep doesnt_matter_what_you_grep | wc -l && echo "true"vspsql -l | grep it_does_matter_here && echo "only true if grep returns anything"
Mike Lyons

2
すべての切断とは何ですか?最初の列だけを見ていることを確認したい場合は、それをregex:に入れるだけで、psql -l | grep '^ exact_dbname\b'見つからない場合に終了コードが設定されます。
スティーブベネット、

21

postgresqlは初めてですが、次のコマンドは、データベースが存在するかどうかを確認するために使用したものです

if psql ${DB_NAME} -c '\q' 2>&1; then
   echo "database ${DB_NAME} exists"
fi

9
さらに簡略化できますpsql ${DB_NAME} -c ''
Pedro Romano 14

2
私にはよく見えますが、データベースは存在するが、接続できない場合は偽陰性の可能性があります(おそらく許可されますか?)
Steve Bennett

7
@SteveBennett、必要なDBに対する権限がない場合、それは存在しません:)
Viacheslav Dobromyslov

9

次の方法を使用して、データベースがまだ存在しない場合は作成できます。

if [[ -z `psql -Atqc '\list mydatabase' postgres` ]]; then createdb mydatabase; fi

9

私は簡潔でPOSIX互換の形式に他の答えを組み合わせています:

psql -lqtA | grep -q "^$DB_NAME|"

true0)の戻りは、それが存在することを意味します。

データベース名になどの非標準文字が含まれていると思われる$場合は、少し長いアプローチが必要です。

psql -lqtA | cut -d\| -f1 | grep -qxF "$DB_NAME"

-tおよび-Aオプションは、出力が生および「表形式」または空白詰め出力されていないことを確認してください。列はパイプ文字|で区切られているため、cutまたははgrepこれを認識する必要があります。最初の列にはデータベース名が含まれています。

編集:部分的な名前の一致を防ぐために-xを指定したgrep。


6
#!/bin/sh
DB_NAME=hahahahahahaha
psql -U postgres ${DB_NAME} --command="SELECT version();" >/dev/null 2>&1
RESULT=$?
echo DATABASE=${DB_NAME} RESULT=${RESULT}
#

+1因果散発的な使用については、私は他の答えを選びますが、ルーチンスクリプトの場合、これはよりクリーンで堅牢です。警告:ユーザー 'postgres'がパスワードなしで接続できることを確認してください。
leonbloy 2013年

はい、必要なユーザー名に関して問題があります。OTOH:接続権限のない他のロールを使いたくないでしょう。
wildplasser 2013年

3

完全を期すために、文字列カットではなく正規表現を使用する別のバージョン:

psql -l | grep '^ exact_dbname\b'

たとえば:

if psql -l | grep '^ mydatabase\b' > /dev/null ; then
  echo "Database exists already."
  exit
fi

を使用\bすると、を使用したすべての回答と同じ問題grep -wがあります。つまり、データベース名にはのような非単語構成文字を含めることができる-ため、照合しようとするfooとも照合されfoo-barます。
フィル2016

2

kibibuの受け入れられた回答は、指定されたパターンを単語構成要素として含むすべての名前にgrep -w一致するという点で欠陥があります。

つまり、「foo」を検索すると、「foo-backup」が一致します。

オセウスの答えはいくつかの優れた改善を提供し、短いバージョンはほとんどの場合正しく動作しますが、提供される2つのバリアントのうち長い方は、部分文字列の一致に関して同様の問題を示します。

この問題を解決するには、POSIX -x引数を使用して、テキストの行全体のみを照合します。

オセウスの答えに基づいて、新しいバージョンは次のようになります。

psql -U "$USER" -lqtA | cut -d\| -f1 | grep -qFx "$DBNAME"

とはいえ、特定のデータベースについて実際にpostgresに質問するNicolas Grillyの回答が、すべての中で最も優れたアプローチであると言える傾向があります。


2

他のソリューション(これは素晴らしい)は、psqlがホストに接続できない場合、タイムアウトする前に1分以上待機する可能性があるという事実を見逃しています。だから、私はタイムアウトを3秒に設定するこのソリューションが好きです:

PGCONNECT_TIMEOUT=3 psql development -h db -U postgres -c ""

これは、公式のpostgres Alpine Dockerイメージ上の開発データベースに接続するためのものです。

それとは別に、Railsを使用していて、データベースがまだ存在しない場合にデータベースをセットアップする場合(Dockerコンテナーを起動するときなど)、移行はべき等であるため、これはうまく機能します。

bundle exec rake db:migrate 2>/dev/null || bundle exec rake db:setup


0

私はまだシェルプログラミングにまだ慣れていないので、これがなんらかの理由で本当に間違っている場合は、投票してください。

キビブの答えから構築:

# If resulting string is not zero-length (not empty) then...
if [[ ! -z `psql -lqt | cut -d \| -f 1 | grep -w $DB_NAME` ]]; then
  echo "Database $DB_NAME exists."
else
  echo "No existing databases are named $DB_NAME."
fi
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.