Проверьте, существует ли база данных в PostgreSQL с помощью shell

Мне было интересно, сможет ли кто-нибудь рассказать мне о том, можно ли использовать shell для проверки наличия базы данных PostgreSQL?

Я делаю сценарий оболочки, и я только хочу, чтобы он создал базу данных, если она еще не существует, но до сих пор не смогла увидеть, как ее реализовать.

12 ответов


я использую следующую модификацию решения Артуро:

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)

использование наивного подхода означает, что поиск базы данных под названием "Список"," доступ "или" строки " будет успешным. Поэтому мы передаем этот вывод через кучу встроенных инструментов командной строки только для поиска в первом столбце.


на -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 в этом случае. The -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

следующий код оболочки, кажется, работает для меня:

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 в противном случае.

кроме того, если вы попытаетесь создать базу данных, которая уже существует, 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|"

возвращение true (0) означает, что он существует.

если вы подозреваете, что имя вашей базы данных может иметь нестандартный символ, такой как $, вам нужен немного более длинный подход:

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

на -t и -A параметры убедитесь, что вывод является необработанным, а не "табличным" или заполненным пробелами. Столбцы разделяются символом трубы |, так что либо cut или grep должен признать это. Первый столбец содержит имя базы данных.

EDIT: 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}
#

вы можете создать базу данных, если она уже не существует, используя этот метод:

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

для полноты другая версия, использующая регулярное выражение, а не резку строк:

psql -l | grep '^ exact_dbname\b'

например:

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

kibibu это принято отвечать имеет недостатки в этом grep -w будет соответствовать любой имя, содержащее указанный шаблон в качестве компонента word.

т. е. если вы ищете "foo", то" foo-backup " соответствует.

Otheus это обеспечивает некоторые хорошие улучшения, и короткая версия будет работать правильно в большинстве случаев, но более длинный из двух предложенных вариантов демонстрирует аналогичную проблему с соответствующими подстроками.

В решить эту проблему, мы можем использовать POSIX -x аргумент для соответствия только весь строки текста.

основываясь на ответе Отеуса, новая версия выглядит так:

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

этим все сказано, я склонен сказать, что ответ Николя Грилли -- где вы на самом деле спрашиваете postgres о конкретной базе данных-это лучший подход из всех.


Я все еще довольно неопытен в программировании оболочки, поэтому, если это действительно неправильно по какой-то причине, проголосуйте за меня, но не слишком тревожьтесь.

здание из ответа кибибу:

# 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 }'|grep -w <database>

более короткая версия


другие решения (которые являются фантастическими) упускают тот факт, что psql может подождать минуту или больше до тайм-аута, если он не может подключиться к хосту. Итак, мне нравится это решение, которое задает таймаут в 3 секунды:

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

Это для подключения к базе данных разработки на официальном postgres изображение Alpine Docker.

отдельно, если вы используете Rails и хотите настроить базу данных, если она еще не существует (как при запуске Докера container), это хорошо работает, так как миграции идемпотентны:

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