Respostas:
Eu uso a seguinte modificação da solução do Arturo:
psql -lqt | cut -d \| -f 1 | grep -qw <db_name>
psql -l
gera algo como o seguinte:
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)
Usar uma abordagem ingênua significa que a busca por um banco de dados chamado "Lista", "Acesso" ou "linhas" será bem-sucedida. Portanto, canalizamos essa saída através de várias ferramentas de linha de comando internas para pesquisar apenas na primeira coluna.
A -t
bandeira remove cabeçalhos e rodapés:
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
O próximo bit cut -d \| -f 1
divide a saída pelo |
caractere de tubo vertical (escapou do shell com uma barra invertida) e seleciona o campo 1. Isso deixa:
my_db
postgres
template0
template1
grep -w
corresponde a palavras inteiras e, portanto, não corresponderá se você estiver pesquisando temp
nesse cenário. A -q
opção suprime qualquer saída gravada na tela; portanto, se você deseja executá-lo interativamente em um prompt de comando, pode excluir o valor-q
item para que algo seja exibido imediatamente.
Observe que grep -w
corresponde a alfanuméricos, dígitos e o sublinhado, que é exatamente o conjunto de caracteres permitido nos nomes de banco de dados não citados no postgresql (hífens não são legais em identificadores não citados). Se você estiver usando outros caracteres, grep -w
não funcionará para você.
O status de saída de todo esse pipeline será 0
(êxito) se o banco de dados existir ou 1
(falha) se não existir . Seu shell definirá a variável especial $?
para o status de saída do último comando. Você também pode testar o status diretamente em uma condição:
if psql -lqt | cut -d \| -f 1 | grep -qw <db_name>; then
# database exists
# $? is 0
else
# ruh-roh
# $? is 1
fi
wc
inteiramente. Veja minha revisão. (Se você quiser reverter o status de saída, Bash suporta um operador de estrondo: ! psql ...
)
wc
comando, eu usaria grep -qw <term>
. Isso fará com que o shell retorne 0
se houver uma correspondência ou 1
não. Em seguida, $?
conterá o valor de retorno e você poderá usá-lo para decidir o que fazer a seguir. Portanto, eu recomendo não usar wc
neste caso. grep
fará o que você precisa.
O seguinte código shell parece funcionar para mim:
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
psql -U user -tAc "SELECT 1 FROM pg_database WHERE datname='DB_NAME'" template1
if [[ $(...) == 1* ]]
postgres@desktop:~$ psql -l | grep <exact_dbname> | wc -l
Isso retornará 1 se o banco de dados especificado existir ou 0 caso contrário.
Além disso, se você tentar criar um banco de dados que já existe, o postgresql retornará uma mensagem de erro como esta:
postgres@desktop:~$ createdb template1
createdb: database creation failed: ERROR: database "template1" already exists
exact_dbname_test
existiria? A única maneira de testar é tentar se conectar a ele.
psql -l | grep doesnt_matter_what_you_grep | wc -l && echo "true"
vspsql -l | grep it_does_matter_here && echo "only true if grep returns anything"
psql -l | grep '^ exact_dbname\b'
que define um código de saída se não for encontrado.
Eu sou novo no postgresql, mas o comando a seguir é o que eu costumava verificar se existe um banco de dados
if psql ${DB_NAME} -c '\q' 2>&1; then
echo "database ${DB_NAME} exists"
fi
psql ${DB_NAME} -c ''
.
Você pode criar um banco de dados, se ele ainda não existir, usando este método:
if [[ -z `psql -Atqc '\list mydatabase' postgres` ]]; then createdb mydatabase; fi
Estou combinando as outras respostas para um formulário sucinto e compatível com POSIX:
psql -lqtA | grep -q "^$DB_NAME|"
Um retorno de true
(0
) significa que existe.
Se você suspeitar que o nome do banco de dados possa ter um caractere não padrão, por exemplo $
, precisará de uma abordagem um pouco mais:
psql -lqtA | cut -d\| -f1 | grep -qxF "$DB_NAME"
As opções -t
e -A
garantem que a saída seja bruta e não "tabular" ou preenchida com espaço em branco. As colunas são separadas pelo caractere de barra vertical |
, portanto, o cut
ou ogrep
deve reconhecer isso. A primeira coluna contém o nome do banco de dados.
EDIT: grep com -x para evitar correspondências parciais de nomes.
#!/bin/sh
DB_NAME=hahahahahahaha
psql -U postgres ${DB_NAME} --command="SELECT version();" >/dev/null 2>&1
RESULT=$?
echo DATABASE=${DB_NAME} RESULT=${RESULT}
#
Para completar, outra versão usando regex, em vez de corte de cadeia:
psql -l | grep '^ exact_dbname\b'
Então, por exemplo:
if psql -l | grep '^ mydatabase\b' > /dev/null ; then
echo "Database exists already."
exit
fi
\b
tem o mesmo problema que todas as respostas grep -w
que usam, como nomes de bancos de dados podem conter caracteres que não sejam constituintes de palavras -
e, portanto, as tentativas de correspondência foo
também serão correspondentes foo-bar
.
A resposta aceita de kibibu é falha, pois grep -w
corresponde a qualquer nome que contenha o padrão especificado como um componente de palavra.
ou seja, se você procurar "foo", então "foo-backup" é uma correspondência.
Resposta de Otheus fornece algumas boas melhorias, e a versão curta funcionará corretamente na maioria dos casos, mas a mais longa das duas variantes oferecidas exibe um problema semelhante com a correspondência de substrings.
Para resolver esse problema, podemos usar o -x
argumento POSIX para corresponder apenas a linhas inteiras do texto.
Com base na resposta de Otheus, a nova versão fica assim:
psql -U "$USER" -lqtA | cut -d\| -f1 | grep -qFx "$DBNAME"
Dito isso, estou inclinado a dizer que a resposta de Nicolas Grilly - onde você realmente pergunta ao postgres sobre o banco de dados específico - é a melhor abordagem de todas.
As outras soluções (que são fantásticas) perdem o fato de que o psql pode esperar um minuto ou mais antes de atingir o tempo limite, se não conseguir se conectar a um host. Então, eu gosto desta solução, que define o tempo limite para 3 segundos:
PGCONNECT_TIMEOUT=3 psql development -h db -U postgres -c ""
Isso é para conectar-se a um banco de dados de desenvolvimento na imagem oficial do Alpine Docker do postgres .
Separadamente, se você estiver usando o Rails e quiser configurar um banco de dados, se ele ainda não existir (como ao iniciar um contêiner do Docker), isso funcionará bem, pois as migrações são idempotentes:
bundle exec rake db:migrate 2>/dev/null || bundle exec rake db:setup
Eu ainda sou bastante inexperiente com a programação de shell, por isso, se isso estiver realmente errado por algum motivo, vote-me, mas não fique muito alarmado.
Construindo a partir da resposta 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
... | grep 0
para fazer com que o valor de retorno do shell seja 0 se o banco de dados não existir e 1 se existir; ou... | grep 1
para o comportamento oposto