PostgreSQL'de veritabanı olup olmadığını kabuk kullanarak kontrol edin


130

Bir PostgreSQL veritabanının var olup olmadığını kontrol etmek için kabuk kullanmanın mümkün olup olmadığını kimse bana söyleyebilir mi?

Bir kabuk komut dosyası yapıyorum ve veritabanını yalnızca zaten mevcut değilse ancak şimdiye kadar nasıl uygulanacağını göremediyse oluşturmasını istiyorum.

Yanıtlar:


199

Arturo'nun çözümünde aşağıdaki değişikliği kullanıyorum:

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


Bu ne yapar

psql -l aşağıdaki gibi bir çıktı verir:

                                        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)

Saf yaklaşımı kullanmak, "Liste," Erişim "veya" satırlar "adlı bir veritabanının aranmasının başarılı olacağı anlamına gelir. Bu nedenle, bu çıktıyı, yalnızca ilk sütunda arama yapmak için bir dizi yerleşik komut satırı aracıyla yönlendiririz.


-tBayrak üstbilgi ve altbilgi kaldırır:

 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

Sonraki bit, cut -d \| -f 1çıktıyı dikey boru |karakteriyle böler (ters eğik çizgiyle kabuktan kaçtı) ve alan 1'i seçer. Bu,:

 my_db             
 postgres          
 template0         

 template1         

grep -wtam kelimelerle eşleşir ve bu nedenle, tempbu senaryoda arıyorsanız, eşleşmez . Bu -qseçenek, ekrana yazılan herhangi bir çıktıyı bastırır, bu nedenle bunu bir komut isteminde etkileşimli olarak çalıştırmak istiyorsanız, bir -qşeyin hemen görüntülenmesini sağlamak için onu dışlayabilirsiniz .

grep -wAlfasayısal, rakamlar ve alt çizgi ile eşleştiğini unutmayın; bu, tam olarak postgresql'deki alıntılanmamış veritabanı adlarında izin verilen karakter kümesidir (tireler tırnaksız tanımlayıcılarda geçerli değildir). Başka karakterler kullanıyorsanız, grep -wsizin için çalışmayacaktır.


Tüm bu ardışık düzenin çıkış durumu 0veritabanı varsa (başarılı) veya yoksa 1(başarısız) olacaktır. Kabuğunuz özel değişkeni $?son komutun çıkış durumuna ayarlayacaktır . Durumu doğrudan bir koşulda da test edebilirsiniz:

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

8
Ayrıca ... | grep 0, DB yoksa, kabuk dönüş değerini 0, varsa 1 yapmak için de ekleyebilirsiniz ; ya ... | grep 1da tersi davranış için
acjay

2
@ acjohnson55 daha da iyi: wctamamen bırakın . Revizyonuma bakın. (Eğer çıkış durumu tersine çevirmek için, Bash bir patlama operatörü destekler: ! psql ...)
BENESCH

Şimdi bunu görüyorum, güzel
vol7ron

1
wcKomutu bırakmayı öneren diğerlerine ek olarak , kullanırdım grep -qw <term>. Bu, 0bir eşleşme varsa veya 1aksi takdirde kabuğun geri dönmesine neden olur . Ardından, $?dönüş değerini içerecek ve daha sonra ne yapacağınıza karar vermek için bunu kullanabilirsiniz. Bu nedenle, wcbu durumda kullanmamanızı tavsiye ederim . grepihtiyacın olanı yapacak.
Matt Friedman

Geri bildiriminize göre bu yanıtı güncellemeye başladım. Hepinize teşekkürler.
kibibu

81

Aşağıdaki kabuk kodu benim için çalışıyor gibi görünüyor:

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

1
Herhangi bir harici cut grep wc ve benzeri şeyler üzerinde geçiş yapmamanızı seviyorum .. db varlığını kontrol ediyorsunuz, bu da en azından psql'ye sahip olduğunuz anlamına geliyor, ant bu en az ve kullandığınız komuttur! gerçekten çok iyi. Ayrıca konu, kabuk tipinden veya komut versiyonundan veya dağıtımından bahsetmedi .. Bunu bildiğim için diğer cevaplarda gördüğüm sistem araçlarına bu kadar çok sayıda boru dememiştim. Yıllar sonra ortaya çıkan sorunlara yol açar
Riccardo Manfrin

1
@RiccardoManfrin'e katılıyorum, bu daha doğrudan bir çözüm gibi görünüyor.
Travis

Bunu postgres kullanıcısı olmayan bir kullanıcıyla gerçekleştirmeniz gerekiyorsa, -U kullanıcısı ekleyebilirsiniz, ancak bağlanmak için bir veritabanı listelemeniz gerekir, çünkü hiçbiri mevcut olmadığından, her zaman var olan postgres şablon1 veritabanını kullanabilirsiniz: psql -U user -tAc "SELECT 1 FROM pg_database WHERE datname='DB_NAME'" template1
Ocak

Cygwin'de psql, çıktıya ('1 \ C-M') garip kontrol karakterleri ekler ve çıktının yalnızca 1:if [[ $(...) == 1* ]]
Ocak

28
postgres@desktop:~$ psql -l | grep <exact_dbname> | wc -l

Bu, belirtilen veritabanı varsa 1 veya aksi takdirde 0 döndürür.

Ayrıca, zaten var olan bir veritabanı oluşturmaya çalışırsanız, postgresql aşağıdaki gibi bir hata mesajı döndürür:

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

10
İlk öneri çok tehlikelidir. Ne olurdu exact_dbname_test? Test etmenin tek yolu ona bağlanmaya çalışmaktır.
wildplasser

6
Bu cevap sağlam değil! Arama teriminiz başka bir sütunda görünüyorsa sıfır olmayan sayıları yazdırır (döndürmez!). Bunu yapmanın daha doğru bir yolu için lütfen kibibu'nun cevabına bakın.
acjay

1
"grep -w foo", "foo-bar" adlı bir veritabanı mevcut olduğunda size yanlış pozitifler verebilir. Tüm kelimeleri psql çıktı başlığında bulacağından bahsetmiyorum bile.
Marius Gedminas

1
bu cevaba kesinlikle katılmıyorum. Bu ifadeyi mantıksal bir ifadede kullanırsanız HER ZAMAN doğru olacaktır. aşağıdaki örnekleri test etmek için deneyebilirsiniz: 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"
Mike Lyons

2
Tüm bu kesim ne olacak? Yalnızca ilk sütuna baktığınızdan emin olmak istiyorsanız, onu normal ifadeye koyun: psql -l | grep '^ exact_dbname\b'bulunmazsa bir çıkış kodu ayarlar.
Steve Bennett

21

Postgresql'de yeniyim, ancak aşağıdaki komut bir veritabanı olup olmadığını kontrol etmek için kullandığım şeydi

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

9
Daha da basitleştirilebilir psql ${DB_NAME} -c ''.
Pedro Romano

2
Bana iyi görünüyor, ancak veritabanı varsa yanlış negatif olabilir, ancak ona bağlanamazsınız (belki kalıcıdır?)
Steve Bennett

7
@SteveBennett, gerekli DB için herhangi bir izniniz yoksa, o zaman sizin için mevcut değildir :)
Viacheslav Dobromyslov

10

Henüz yoksa, şu yöntemi kullanarak bir veritabanı oluşturabilirsiniz:

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

9

Diğer cevapları kısa ve POSIX uyumlu bir forma birleştiriyorum:

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

true( 0) Dönüşü var olduğu anlamına gelir.

Veritabanı adınızın standart olmayan bir karaktere sahip olabileceğinden şüpheleniyorsanız, $biraz daha uzun bir yaklaşıma ihtiyacınız var:

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

-tVe -Aseçenekler çıktı ham ve "sekmeli" veya boşluk-yastıklı çıktı olmadığından emin olun. Sütunlar dikey çizgi karakteriyle ayrılır |, bu nedenle ya cutya da grepsütunun bunu tanıması gerekir. İlk sütun, veritabanı adını içerir.

DÜZENLEME: kısmi ad eşleşmelerini önlemek için -x ile grep.


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

+1 Ara sıra nedensel kullanım için, diğer cevabı seçerdim, ancak rutin bir komut dosyası için bu daha temiz ve sağlam. Uyarı: "postgres" kullanıcısının parola olmadan bağlanıp bağlanamadığını kontrol edin.
leonbloy

Evet, ihtiyaç duyulan kullanıcı adıyla ilgili bir sorun var. OTOH: Bağlantı izni olmayan başka bir rol kullanmak istemezsiniz.
wildplasser

3

Tamlık için, dize kesme yerine normal ifadeyi kullanan başka bir sürüm:

psql -l | grep '^ exact_dbname\b'

Yani örneğin:

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

Kullanmak \b, kullanan tüm yanıtlarla aynı soruna sahiptir; grep -wbu, veritabanı adlarının, gibi sözcük olmayan karakterleri içerebildiği -ve bu nedenle eşleştirme girişimleri foode eşleşecektir foo-bar.
phils

2

kibibu'nun kabul ettiği yanıt , bir kelime bileşeni olarak belirtilen kalıbı içeren herhangi bir adla grep -weşleşecek şekilde kusurludur .

Yani "foo" ararsanız, "foo-yedekleme" bir eşleşmedir.

Otheus'un cevabı bazı iyi iyileştirmeler sağlar ve kısa versiyon çoğu durumda doğru çalışacaktır, ancak sunulan iki varyanttan daha uzun olanı, eşleşen alt dizelerle benzer bir sorun sergiler.

Bu sorunu çözmek için, POSIX -xargümanını yalnızca eşleşecek şekilde kullanabiliriz metnin tüm satırlarını .

Otheus'un cevabına dayanan yeni sürüm şuna benzer:

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

Tüm bunlarla birlikte , Nicolas Grilly'nin cevabının - aslında postgres'e spesifik veri tabanı hakkında sorduğunuz yerde - hepsinin en iyi yaklaşımı olduğunu söylemeye meyilliyim .


2

Diğer çözümler (harika), psql'nin bir ana bilgisayara bağlanamaması durumunda zaman aşımına uğramadan önce bir dakika veya daha fazla bekleyebileceği gerçeğini gözden kaçırır. Bu yüzden, zaman aşımını 3 saniyeye ayarlayan bu çözümü beğendim:

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

Bu, resmi postgres Alpine Docker görüntüsündeki bir geliştirme veritabanına bağlanmak içindir .

Ayrı olarak, Rails kullanıyorsanız ve zaten mevcut değilse (bir Docker konteyneri başlatırken olduğu gibi) bir veritabanı kurmak istiyorsanız, geçişler idempotent olduğundan bu iyi çalışır:

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

1

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

daha kısa versiyon


0

Kabuk programlamada hala oldukça deneyimsizim, bu yüzden bu bir sebepten dolayı gerçekten yanlışsa, beni oylayın, ama fazla endişelenmeyin.

Kibibu'nun cevabından yola çıkarak:

# 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
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.