web-dev-qa-db-ja.com

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

シェルを使用してPostgreSQLデータベースが存在するかどうかを確認できるかどうかを誰かが教えてくれるかどうか疑問に思っていました。

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

110
Jimmy

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
171
kibibu

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

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
64
Nathan Osman
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
25
Arturo

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

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

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

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

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

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

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

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

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

10
Otheus

このメソッドを使用して、データベースがまだ存在しない場合は作成できます。

if [[ -z `psql -Atqc '\list mydatabase' postgres` ]]; then createdb mydatabase; fi
8
Nicolas Grilly
#!/bin/sh
DB_NAME=hahahahahahaha
psql -U postgres ${DB_NAME} --command="SELECT version();" >/dev/null 2>&1
RESULT=$?
echo DATABASE=${DB_NAME} RESULT=${RESULT}
#
5
wildplasser

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

psql -l | grep '^ exact_dbname\b'

したがって、たとえば:

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

kibibuの 受け入れられた回答 には、grep -wがWordコンポーネントとして指定されたパターンを含む名前anyと一致するという点で欠陥があります。

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

オテウスの答え はいくつかの良い改善を提供し、短いバージョンはほとんどの場合正しく動作しますが、提供される2つのバリアントのうち長い方は、部分文字列のマッチングで同様の問題を示します。

この問題を解決するには、POSIX -x引数を使用して、テキストのentire行のみに一致させることができます。

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

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

とはいえ、私は Nicolas Grillyの答え -特定のデータベースについてpostgresに実際に尋ねる-がすべての最良のアプローチであると言いたいと思います。

2
phils

psql -l|awk '{print $1}'|grep -w <database>

短いバージョン

1
Justin

他のソリューション(素晴らしい)は、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
Dan Kohn

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

Kibibuの答えから構築:

# 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
0
David Winiecki