Kiểm tra xem cơ sở dữ liệu có tồn tại trong PostgreSQL bằng shell không


130

Tôi đã tự hỏi nếu có ai có thể cho tôi biết liệu có thể sử dụng shell để kiểm tra xem cơ sở dữ liệu PostgreQuery có tồn tại không?

Tôi đang tạo một kịch bản shell và tôi chỉ muốn nó tạo cơ sở dữ liệu nếu nó không tồn tại nhưng cho đến nay vẫn chưa thể thấy cách triển khai nó.

Câu trả lời:


199

Tôi sử dụng sửa đổi sau đây của giải pháp của Arturo:

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


Những gì nó làm

psql -l xuất ra một cái gì đó như sau:

                                        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)

Sử dụng cách tiếp cận ngây thơ có nghĩa là tìm kiếm cơ sở dữ liệu có tên "Danh sách", "Truy cập" hoặc "hàng" sẽ thành công. Vì vậy, chúng tôi dẫn đầu ra này thông qua một loạt các công cụ dòng lệnh tích hợp để chỉ tìm kiếm trong cột đầu tiên.


Các -tcờ loại bỏ tiêu đề và chân trang:

 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

Bit tiếp theo, cut -d \| -f 1phân tách đầu ra theo |ký tự ống đứng (thoát khỏi vỏ bằng dấu gạch chéo ngược) và chọn trường 1. Điều này để lại:

 my_db             
 postgres          
 template0         

 template1         

grep -wkhớp toàn bộ từ và vì vậy sẽ không khớp nếu bạn đang tìm kiếm temptrong kịch bản này. Các -qtùy chọn ngăn chặn bất kỳ đầu ra bằng văn bản cho màn hình, vì vậy nếu bạn muốn chạy này một cách tương tác tại dấu nhắc lệnh bạn có thể có để loại trừ-q một cái gì đó để được hiển thị ngay lập tức.

Lưu ý rằng grep -wkhớp với chữ và số, chữ số và dấu gạch dưới, chính xác là tập hợp các ký tự được phép trong tên cơ sở dữ liệu không được trích dẫn trong postgresql (dấu gạch nối không hợp pháp trong số nhận dạng không được trích dẫn). Nếu bạn đang sử dụng các nhân vật khác, grep -wsẽ không làm việc cho bạn.


Trạng thái thoát của toàn bộ đường ống này sẽ là 0(thành công) nếu cơ sở dữ liệu tồn tại hoặc 1(thất bại) nếu không. Shell của bạn sẽ đặt biến đặc biệt $?thành trạng thái thoát của lệnh cuối cùng. Bạn cũng có thể kiểm tra trạng thái trực tiếp trong một điều kiện:

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

8
Bạn cũng có thể thêm ... | grep 0để làm cho giá trị trả về shell là 0 nếu DB không tồn tại và 1 nếu có; hoặc ... | grep 1cho hành vi ngược lại
acjay

2
@ acjohnson55 thậm chí tốt hơn: thả wchoàn toàn. Xem bản sửa đổi của tôi. (Nếu bạn muốn đảo ngược trạng thái thoát, Bash hỗ trợ toán tử bang ! psql ...:)
benesch

Chỉ cần nhìn thấy điều này, tốt đẹp
vol7ron

1
Hơn nữa để đề nghị bỏ wclệnh, tôi sẽ sử dụng grep -qw <term>. Điều này sẽ khiến vỏ trở lại 0nếu có một trận đấu và 1nếu không. Sau đó, $?sẽ chứa giá trị trả về và bạn có thể sử dụng giá trị đó để quyết định làm gì tiếp theo. Vì vậy, tôi khuyên bạn không nên sử dụng wctrong trường hợp này. grepsẽ làm những gì bạn cần.
Matt Friedman

Tôi có xung quanh để cập nhật câu trả lời này dựa trên phản hồi của bạn. Cảm ơn tất cả.
kibibu

81

Mã shell sau đây dường như hoạt động với tôi:

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
Tôi thích rằng bạn không chuyển tiếp trên bất kỳ grep wc và công cụ cắt bên ngoài nào .. bạn kiểm tra sự tồn tại của db, điều đó có nghĩa là bạn có ít nhất psql, ant đó là lệnh ít nhất và duy nhất bạn sử dụng! thực sự rất tốt đẹp Bên cạnh đó, đối tượng không đề cập đến loại vỏ cũng như phiên bản lệnh hoặc bản phân phối .. Tôi sẽ không bao giờ chuyển tiếp vào một loạt các đường ống như vậy đến công cụ hệ thống mà tôi đã thấy trên các câu trả lời khác để biết điều đó. Nó dẫn đến các vấn đề nhiều năm sau
Riccardo Manfrin

1
Tôi đồng ý với @RiccardoManfrin đây có vẻ là giải pháp trực tiếp hơn.
Travis

Nếu bạn cần phải thực hiện điều này với những người không sử dụng postgres bạn có thể thêm người dùng -U, nhưng phải liệt kê một cơ sở dữ liệu để kết nối với, như không thể tồn tại, bạn có thể sử dụng postgres template1 cơ sở dữ liệu luôn luôn tồn tại: psql -U user -tAc "SELECT 1 FROM pg_database WHERE datname='DB_NAME'" template1
Tháng Một

Trong psql Cygwin thêm ký tự điều khiển xa lạ đối với đầu ra ( '1 \ C-M') và một nhu cầu để kiểm tra xem các đầu ra chỉ bắt đầu với 1:if [[ $(...) == 1* ]]
Tháng Một

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

Điều này sẽ trả về 1 nếu cơ sở dữ liệu được chỉ định tồn tại hoặc 0 nếu không.

Ngoài ra, nếu bạn cố gắng tạo một cơ sở dữ liệu đã tồn tại, postgresql sẽ trả về một thông báo lỗi như thế này:

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

10
Gợi ý đầu tiên là rất nguy hiểm. Điều gì sẽ xảy ra exact_dbname_testsẽ tồn tại? Cách duy nhất để thử nghiệm là cố gắng kết nối với nó.
wildplasser

6
Câu trả lời này không mạnh mẽ! Nó in (không trả về!) Các số khác không nếu cụm từ tìm kiếm của bạn xuất hiện trong một cột khác. Xin vui lòng xem câu trả lời của kibibu để biết cách chính xác hơn để làm điều này.
acjay

1
"grep -w foo" có thể cung cấp cho bạn dương tính giả khi cơ sở dữ liệu có tên "foo-bar" tồn tại. Chưa kể nó sẽ tìm thấy tất cả các từ trong tiêu đề đầu ra psql.
Marius Gedminas

1
tôi hoàn toàn không đồng ý với câu trả lời này Nó sẽ luôn luôn đúng nếu bạn sử dụng biểu thức này trong một câu lệnh logic. bạn có thể thử các ví dụ này để kiểm tra: 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
Những gì với tất cả các cắt? Nếu bạn muốn đảm bảo rằng bạn chỉ nhìn vào cột đầu tiên, chỉ cần đặt nó vào regex : psql -l | grep '^ exact_dbname\b', nó đặt mã thoát nếu không tìm thấy.
Steve Bennett

21

Tôi mới sử dụng postgresql, nhưng lệnh sau đây là những gì tôi đã sử dụng để kiểm tra xem cơ sở dữ liệu có tồn tại không

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

9
Có thể được đơn giản hóa hơn nữa để psql ${DB_NAME} -c ''.
Pedro Romano

2
Có vẻ tốt với tôi, mặc dù nó có thể sai âm nếu cơ sở dữ liệu tồn tại nhưng bạn không thể kết nối với nó (có thể không?)
Steve Bennett

7
@SteveBennett, nếu bạn không có bất kỳ quyền nào đối với DB được yêu cầu thì nó không tồn tại cho bạn :)
Viacheslav Dobromyslov

9

Bạn có thể tạo cơ sở dữ liệu, nếu nó chưa tồn tại, sử dụng phương pháp này:

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

9

Tôi đang kết hợp các câu trả lời khác với dạng tương thích ngắn gọn và POSIX:

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

Một sự trở lại của true( 0) có nghĩa là nó tồn tại.

Nếu bạn nghi ngờ tên cơ sở dữ liệu của bạn có thể có một ký tự không chuẩn như $, bạn cần một cách tiếp cận dài hơn một chút:

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

Các tùy chọn -t-Ađảm bảo đầu ra là thô và không phải là "bảng" hoặc đầu ra có khoảng trắng. Các cột được phân tách bằng ký tự ống |, do đó, cuthoặc grepphải nhận ra điều này. Cột đầu tiên chứa tên cơ sở dữ liệu.

EDIT: grep với -x để ngăn khớp tên một phần.


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 Để sử dụng lẻ tẻ nguyên nhân, tôi sẽ chọn câu trả lời khác, nhưng đối với tập lệnh thông thường, điều này rõ ràng và mạnh mẽ hơn. Hãy cẩn thận: kiểm tra xem người dùng 'postgres' có thể không thể nhập mật khẩu hay không.
leonbloy

Có một vấn đề về tên người dùng đang cần. OTOH: bạn sẽ không muốn sử dụng một vai trò khác không có quyền kết nối.
wildplasser

3

Để hoàn thiện, một phiên bản khác sử dụng regex thay vì cắt chuỗi:

psql -l | grep '^ exact_dbname\b'

Ví dụ:

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

Việc sử dụng \bcó cùng một vấn đề như tất cả các câu trả lời sử dụng grep -wđó là tên cơ sở dữ liệu có thể chứa các ký tự không cấu thành từ như thế -và do đó các nỗ lực khớp foocũng sẽ khớp foo-bar.
phils

2

Câu trả lời được chấp nhận của kibibu là thiếu sót trong đó grep -wsẽ khớp với bất kỳ tên nào có chứa mẫu được chỉ định làm thành phần từ.

tức là nếu bạn tìm "foo" thì "foo-backup" là khớp.

Câu trả lời của Otheus cung cấp một số cải tiến tốt và phiên bản ngắn sẽ hoạt động chính xác trong hầu hết các trường hợp, nhưng phiên bản dài hơn của hai biến thể được cung cấp cho thấy một vấn đề tương tự với chất nền phù hợp.

Để giải quyết vấn đề này, chúng tôi có thể sử dụng -xđối số POSIX để chỉ khớp với toàn bộ dòng văn bản.

Dựa trên câu trả lời của Otheus, phiên bản mới trông như thế này:

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

Như đã nói, tôi muốn nói rằng câu trả lời của Nicolas Grilly - nơi bạn thực sự hỏi người đăng về cơ sở dữ liệu cụ thể - là cách tiếp cận tốt nhất trong tất cả.


2

Các giải pháp khác (rất tuyệt vời) bỏ lỡ thực tế là psql có thể đợi một phút hoặc hơn trước khi hết thời gian nếu nó không thể kết nối với máy chủ. Vì vậy, tôi thích giải pháp này, đặt thời gian chờ là 3 giây:

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

Điều này là để kết nối với một cơ sở dữ liệu phát triển trên hình ảnh chính thức của Dock Docker postgres .

Một cách riêng biệt, nếu bạn đang sử dụng Rails và muốn thiết lập cơ sở dữ liệu nếu nó chưa tồn tại (như khi khởi chạy một Docker container), thì điều này hoạt động tốt, vì việc di chuyển là tạm thời:

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

1

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

phiên bản ngắn hơn


0

Tôi vẫn còn khá thiếu kinh nghiệm với lập trình shell, vì vậy nếu điều này thực sự sai vì một số lý do, hãy bỏ phiếu cho tôi, nhưng đừng quá hoảng hốt.

Xây dựng từ câu trả lời của 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
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.