使用shell检查PostgreSQL中是否存在数据库

我想知道是否有人能告诉我是否有可能使用shell来检查PostgreSQL数据库是否存在?

我正在做一个shell脚本,我只希望它创build的数据库,如果它不存在,但到现在还没有能够看到如何实现它。

我使用以下修改的Arturo的解决scheme:

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) 

使用简单的方法意味着search名为“List”,“Access”或“rows”的数据库将会成功,所以我们通过一堆内置的命令行工具pipe理这个输出,只在第一列进行search。


-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 cut -d \| -f 1通过垂直pipe道分割输出 字符(使用反斜杠从shell中转义出来),并select字段1.这会留下:

  my_db postgres template0 template1 

grep -w匹配整个单词,因此如果在此scheme中searchtemp ,则不匹配。 -q选项禁止任何输出写入屏幕,所以如果你想在命令提示符下以交互方式运行这个输出,你可以用排除-q立即显示。

请注意, grep -w匹配字母数字,数字和下划线,这正是postgresql中未加引号的数据库名称中允许使用的字符集(连字符在非引号标识符中不合法)。 如果您使用其他字符,则grep -w将不适用于您。


如果数据库存在,整个pipe道的退出状态将为0 (成功),否则为1 (失败)。 你的shell将设置特殊variables$? 到最后一个命令的退出状态。 您也可以直接在条件中testing状态:

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

下面的shell代码似乎适用于我:

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

如果指定的数据库存在,这将返回1,否则返回0。

另外,如果你尝试创build一个已经存在的数据库,postgresql将返回如下错误消息:

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

我是新来的postgresql,但下面的命令是我用来检查数据库是否存在

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

我将其他答案与简洁和POSIX兼容的表单结合起来:

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

返回true0 )意味着它存在。

如果您怀疑数据库名称可能具有诸如$的非标准字符,则需要稍长的方法:

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

-t-A选项确保输出是原始的而不是“表格”或空白填充的输出。 列由pipe道字符分隔 ,所以cutgrep必须认识到这一点。 第一列包含数据库名称。

编辑:grep与-x防止部分名称匹配。

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

您可以使用此方法创build一个数据库(如果它尚不存在):

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

为了完整,使用正则expression式而不是string切割的另一个版本:

 psql -l | grep '^ exact_dbname\b' 

举个例子:

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

kibibu 接受的答案是有缺陷的, grep -w将匹配包含指定模式的任何名称作为单词组件。

即如果你寻找“富”,那么“富备份”是一个匹配。

Otheus的答案提供了一些很好的改进,短版本在大多数情况下都能正常工作,但是提供的两个版本中较长的一个在匹配子string方面performance出类似的问题。

要解决此问题,我们可以使用POSIX -x参数来匹配文本的整个行。

基于奥图斯的回答,新版本看起来像这样:

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

所有人都说,我倾向于说, Nicolas Grilly的回答 – 你真的会问postgres关于具体的数据库 – 是最好的方法。

我对shell编程还相当缺乏经验,所以如果出于某种原因这是错误的,请投我一票,但不要太惊慌。

从kibibu的答案build设:

 # 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 

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

更短的版本

其他解决scheme(非常棒)错过了一个事实,即psql在超时之前可能会等待一分钟或更长时间,如果无法连接到主机。 所以,我喜欢这个解决scheme,它将超时设置为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