157

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

我正在制作一个 shell 脚本,我只希望它创建数据库,如果它不存在但到目前为止还没有看到如何实现它。

4

14 回答 14

225

注意/更新(2021):虽然这个答案有效,但从哲学上讲,我同意其他评论,即正确的方法是询问 Postgres

检查其他答案是否psql -c--command适合您的用例(例如Nicholas Grilly'sNathan Osman'sbruce'sPedro's 变体


我使用 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

下一位,通过垂直管道字符(用反斜杠从 shell 中转义)cut -d \| -f 1拆分输出,并选择字段 1。这留下:|

 my_db             
 postgres          
 template0         
                   
 template1         
         

grep -wtemp匹配整个单词,因此如果您在这种情况下进行搜索,则不会匹配。该-q选项会禁止写入屏幕的任何输出,因此如果您想在命令提示符下交互式地运行它,您可以排除它,-q以便立即显示某些内容。

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


0如果数据库存在,则整个管道的退出状态将为(成功),如果不存在,1则为(失败)。您的 shell 会将特殊变量设置$?为最后一个命令的退出状态。您还可以直接在条件中测试状态:

if psql -lqt | cut -d \| -f 1 | grep -qw <db_name>; then
    # database exists
    # $? is 0
else
    # ruh-roh
    # $? is 1
fi
于 2013-05-28T03:04:49.530 回答
110

以下 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
于 2013-07-20T00:53:24.297 回答
29
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
于 2013-01-27T16:15:24.137 回答
26

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

if psql ${DB_NAME} -c '\q' 2>&1; then
   echo "database ${DB_NAME} exists"
fi
于 2013-03-21T02:05:19.303 回答
12

如果数据库尚不存在,您可以使用以下方法创建数据库:

if [[ -z `psql -Atqc '\list mydatabase' postgres` ]]; then createdb mydatabase; fi
于 2015-12-09T09:12:30.163 回答
9

我将其他答案组合成简洁且 POSIX 兼容的形式:

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

true( )的返回0意味着它存在。

如果您怀疑您的数据库名称可能包含非标准字符,例如$,则需要稍长一点的方法:

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

-tand-A选项确保输出是原始的,而不是“表格”或空格填充的输出。列由竖线字符分隔|,因此 thecut或 thegrep必须识别这一点。第一列包含数据库名称。

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

于 2015-08-18T23:15:01.340 回答
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}
#
于 2013-01-27T16:18:14.003 回答
3

为了完整起见,使用正则表达式而不是字符串切割的另一个版本:

psql -l | grep '^ exact_dbname\b'

例如:

if psql -l | grep '^ mydatabase\b' > /dev/null ; then
  echo "Database exists already."
  exit
fi
于 2014-02-13T12:18:45.823 回答
3

其他解决方案(非常棒)忽略了这样一个事实,即如果 psql 无法连接到主机,它可以等待一分钟或更长时间才能超时。所以,我喜欢这个解决方案,它将超时设置为 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
于 2017-06-27T05:10:53.133 回答
2

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

即,如果您查找“foo”,则“foo-backup”是匹配项。

Otheus 的答案提供了一些很好的改进,并且简短版本在大多数情况下都可以正常工作,但是所提供的两个变体中较长的版本在匹配子字符串方面表现出类似的问题。

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

基于 Otheus 的回答,新版本如下所示:

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

综上所述,我倾向于说Nicolas Grilly 的回答——你实际上向 postgres 询问特定数据库的地方——是最好的方法。

于 2016-03-10T22:53:23.073 回答
2

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

较短的版本

于 2016-11-08T10:18:13.887 回答
1

我对 shell 编程仍然很缺乏经验,所以如果由于某种原因这确实是错误的,请投我反对票,但不要太惊慌。

根据 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
于 2013-10-16T09:30:12.247 回答
0
  • 在一行中:

PGPASSWORD=mypassword psql -U postgres@hostname -h postgres.hostname.com -tAc 'select 1' -d dbnae || echo 0

如果 db 存在则返回 1 如果不存在则返回 0

  • 或更具可读性:
if [ "$(PGPASSWORD=mypassword psql -U postgres@hostname -h postgres.hostname.com -tAc 'select 1' -d dbnae || echo 0 )" = '1' ]
then
    echo "Database already exists"
else
    echo "Database does not exist"
fi
于 2020-10-09T15:57:23.103 回答
0

如果不存在则触发除以零,然后检查返回代码,如下所示:

sql="SELECT 1/count(*) FROM pg_database WHERE datname='db_name'";
error=$(psql -h host -U user -c "$sql" postgres);
if $error
then
  echo "doesn't exist";
else
  echo "exists";
fi
于 2020-10-22T08:56:06.667 回答