151 votes

Vérifier si la base de données existe dans postgreSQL en utilisant le shell

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

Je fais un shell script et je veux seulement qu'il crée la base de données si elle n'existe pas déjà mais jusqu'à présent je n'ai pas pu voir comment l'implémenter.

Merci.

220voto

kibibu Points 2044

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

psql -lqt | cut -d \| -f 1 | grep -w <db_name> | wc -l


Ce qu'il fait

psql -l produit quelque chose comme ce qui suit :

                                        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 "List, "Access" ou "rows" aboutira. Nous faisons donc passer cette sortie par un ensemble d'outils de ligne de commande intégrés pour ne rechercher que dans la première colonne.


Le site -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

La suite, cut -d \| -f 1 divise la sortie par le tuyau vertical | (échappé de l'interpréteur de commandes par une barre oblique inverse), et sélectionne le champ 1. Cela laisse :

 my_db             
 postgres          
 template0         

 template1         

grep -w correspond à des mots entiers, et ne correspondra donc pas si vous recherchez temp dans ce scénario. Et le wc -l compte les lignes de matchine, en donnant 1 si le db existe, et 0 s'il n'existe pas.


Si vous préférez suivre la convention UNIX qui consiste à renvoyer un code de sortie plutôt que d'imprimer la sortie, laissez tomber l'option wc du pipeline :

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

L'état de sortie de ce pipeline sera 0 (succès) si la base de données existe ou 1 (échec) si ce n'est pas le cas. Votre shell définira la variable spéciale $? à l'état de sortie de la dernière commande. Vous pouvez également tester l'état directement dans une conditionnelle :

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

8 votes

Vous pouvez également ajouter ... | grep 0 pour que la valeur de retour du shell soit 0 si le BD n'existe pas et 1 s'il existe ; ou ... | grep 1 pour le comportement opposé

2 votes

@acjohnson55 encore mieux : laissez tomber le wc entièrement. Voir ma révision. (Si vous voulez inverser l'état de sortie, Bash supporte un opérateur bang : ! psql ... )

1 votes

Suite à d'autres suggestions d'abandonner le wc j'utiliserais grep -qw <term> . L'interpréteur de commandes renvoie alors 0 s'il y a une correspondance et 1 sinon. Alors, $? contiendra la valeur de retour et vous pourrez l'utiliser pour décider de ce qu'il faut faire ensuite. Je recommande donc de ne pas utiliser wc dans ce cas. grep fera ce dont vous avez besoin.

101voto

Nathan Osman Points 13475

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

2 votes

J'aime le fait que vous ne vous appuyez pas sur une commande externe, grep wc et autres vous vérifiez l'existence d'une base de données, ce qui suppose que vous avez au moins psql, et que c'est la seule et unique commande que vous utilisez ! très bien en effet. D'ailleurs le sujet ne mentionne pas le type de shell ni la version des commandes ou la distro . Je n'aurais jamais relayé sur une telle pletora de pipes à l'outillage système que j'ai vu sur les autres réponses pour savoir cela. Cela conduit à des problèmes des années plus tard

1 votes

Je suis d'accord avec @RiccardoManfrin, cela semble être la solution la plus directe.

0 votes

Si vous devez effectuer cette opération avec un utilisateur autre que postgres, vous pouvez ajouter -U user, mais vous devrez indiquer une base de données à laquelle vous connecter. Comme il n'en existe aucune, vous pouvez utiliser la base de données postgres template1 qui existe toujours : psql -U user -tAc "SELECT 1 FROM pg_database WHERE datname='DB_NAME'" template1

29voto

Arturo Points 303
postgres@desktop:~$ psql -l | grep <exact_dbname> | wc -l

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

En outre, si vous essayez de créer une base de données qui existe déjà, postgresql renverra un message d'erreur comme celui-ci :

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

A la vôtre.

10 votes

La première suggestion est très dangereuse. Que se passerait-il si exact_dbname_test existerait-elle ? Le seul moyen de le tester est d'essayer de s'y connecter.

6 votes

Cette réponse n'est pas robuste ! Elle imprime (et non renvoie !) des nombres non nuls si votre terme de recherche apparaît dans une autre colonne. Veuillez consulter la réponse de kibibu pour une manière plus correcte de procéder.

1 votes

"grep -w foo" peut vous donner de faux positifs lorsqu'une base de données nommée "foo-bar" existe. Sans compter qu'il trouvera tous les mots dans l'en-tête de sortie de psql.

26voto

bruce Points 89

Je suis nouveau dans le domaine de postgresql, mais la commande suivante est celle que j'ai utilisée pour vérifier si une base de données existe.

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

11 votes

On peut encore simplifier en disant psql ${DB_NAME} -c '' .

2 votes

Cela me semble bon, bien que cela puisse être un faux négatif si la base de données existe mais que vous ne pouvez pas vous y connecter (perms peut-être ?).

8 votes

@SteveBennett, si vous n'avez pas de droits sur la base de données requise, elle n'existe pas pour vous :)

6voto

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

0 votes

+1 Pour une utilisation causale sporadique, j'opterais pour l'autre réponse, mais pour une routine script, celle-ci est plus propre et robuste. Caveat : vérifiez que l'utilisateur 'postgres' peut se connecter sans mot de passe.

0 votes

Oui, il y a un problème avec le fait que le nom d'utilisateur soit nécessaire. Par contre, vous ne voudriez pas utiliser un autre rôle n'ayant pas de permission de connexion.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X