web-dev-qa-db-fra.com

Vérifier si la base de données existe dans PostgreSQL avec un shell

Je me demandais si quelqu'un pourrait me dire s'il est possible d'utiliser Shell pour vérifier si une base de données PostgreSQL existe?

Je suis en train de créer un script Shell et je ne veux que celle-ci crée la base de données si elle n'existe pas déjà, mais jusqu'à présent, je ne savais pas comment la mettre en œuvre.

104
Jimmy

J'utilise la modification suivante de la solution d'Arturo:

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


Ce qu'il fait

psql -l génère quelque chose comme ceci:

                                        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)

L'utilisation de l'approche naïve signifie que la recherche d'une base de données appelée "Liste," Accès "ou" lignes "réussira. Nous dirigeons donc cette sortie vers un ensemble d'outils de ligne de commande intégrés pour rechercher uniquement dans la première colonne.


Le drapeau -t supprime les en-têtes et les pieds de page:

 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

Le bit suivant, cut -d \| -f 1 divise la sortie par le caractère | de tuyau vertical (échappé du shell avec une barre oblique inversée) et sélectionne le champ 1. Cela laisse:

 my_db             
 postgres          
 template0         

 template1         

grep -w correspond aux mots entiers, et donc ne correspondra pas si vous recherchez temp dans ce scénario. L'option -q supprime toute sortie écrite à l'écran. Par conséquent, si vous souhaitez l'exécuter de manière interactive à l'invite d'une commande, vous pouvez exclure le -q afin que quelque chose soit affiché immédiatement.

Notez que grep -w correspond aux caractères alphanumériques, aux chiffres et au trait de soulignement, qui correspond exactement au jeu de caractères autorisé dans les noms de base de données non cités dans postgresql (les traits d'union ne sont pas légaux dans les identificateurs non cités). Si vous utilisez d'autres caractères, grep -w ne fonctionnera pas pour vous.


Le statut de sortie de l'ensemble du pipeline sera 0 (succès) si la base de données existe ou 1 (échec) s'il ne l'est pas. Votre shell définira la variable spéciale $? sur le statut de sortie de la dernière commande. Vous pouvez également tester le statut directement dans une condition:

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

Le code Shell suivant semble fonctionner pour moi:

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
60
Nathan Osman
postgres@desktop:~$ psql -l | grep <exact_dbname> | wc -l

Cela renverra 1 si la base de données spécifiée existe ou 0 sinon.

De plus, si vous essayez de créer une base de données qui existe déjà, postgresql renverra un message d'erreur du type

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

Postgresql est nouveau pour moi, mais la commande suivante m'a permis de vérifier l'existence d'une base de données.

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

Je combine les autres réponses à un formulaire succinct et compatible POSIX:

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

Un retour de true (0) signifie qu'il existe.

Si vous pensez que le nom de votre base de données pourrait avoir un caractère non standard tel que $, vous avez besoin d'une approche légèrement plus longue:

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

Les options -t et -A permettent de s'assurer que la sortie est brute et non "tabulaire" ou complétée par des espaces. Les colonnes sont séparées par le caractère de pipe |. Par conséquent, la variable cut ou la variable grep doit le reconnaître. La première colonne contient le nom de la base de données.

EDIT: grep avec -x pour éviter les correspondances partielles de noms.

10
Otheus

Vous pouvez créer une base de données, si elle n'existe pas déjà, en utilisant cette méthode:

if [[ -z `psql -Atqc '\list mydatabase' postgres` ]]; then createdb mydatabase; fi
7
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

Pour être complet, utilisez une autre version utilisant regex plutôt que la coupe de chaînes:

psql -l | grep '^ exact_dbname\b'

Donc par exemple:

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

réponse acceptée de kibibu est défectueux car grep -w correspondra à tout nom contenant le modèle spécifié en tant que composant Word.

si vous recherchez "foo", alors "foo-backup" est une correspondance.

La réponse d'Otheus apporte de bonnes améliorations, et la version courte fonctionnera correctement dans la plupart des cas, mais la plus longue des deux variantes proposées présente un problème similaire avec les sous-chaînes correspondantes.

Pour résoudre ce problème, nous pouvons utiliser l'argument POSIX -x pour ne faire correspondre que les lignes entières du texte.

S'appuyant sur la réponse d'Otheus, la nouvelle version ressemble à ceci:

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

Cela étant dit, je suis enclin à dire que la réponse de Nicolas Grilly - où vous posez des questions à Postgres au sujet de la base de données spécifique - est la meilleure approche.

2
phils

Les autres solutions (qui sont fantastiques) oublient le fait que psql peut attendre une minute ou plus avant de s’expulser s’il ne parvient pas à se connecter à un hôte. Donc, j'aime bien cette solution, qui fixe le délai d'attente à 3 secondes:

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

Ceci est destiné à la connexion à une base de données de développement sur l'image officielle postgres Alpine Docker.

Séparément, si vous utilisez Rails et souhaitez configurer une base de données si elle n’existe pas déjà (comme lors du lancement d’un conteneur Docker), cela fonctionne bien, car les migrations sont idempotentes:

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

Je ne connais pas encore très bien la programmation Shell. Si cela ne vous convient pas pour une raison quelconque, votez pour moi, mais ne vous inquiétez pas trop.

Construire à partir de la réponse de 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

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

version plus courte

0
Justin