쉘을 사용하여 PostgreSQL에 데이터베이스가 있는지 확인하십시오.


130

셸을 사용하여 PostgreSQL 데이터베이스가 있는지 확인할 수 있는지 여부를 누군가가 말해 줄 수 있는지 궁금합니다.

쉘 스크립트를 만들고 있는데 데이터베이스가 존재하지 않지만 데이터베이스를 구현하는 방법을 볼 수 없었던 경우에만 데이터베이스를 작성하려고합니다.

답변:


199

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)

순진한 접근 방식을 사용한다는 것은 "목록,"액세스 "또는"행 "이라는 데이터베이스를 검색하는 것이 성공한다는 것을 의미하기 때문에이 명령을 내장 명령 줄 도구를 통해 첫 번째 열에서만 검색하도록 파이프합니다.


-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시나리오에서 검색하는 경우 일치하지 않습니다 . 이 -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

8
... | grep 0DB가 존재하지 않으면 쉘 리턴 값을 0으로 설정하고 존재하면 1을 추가 하도록 추가 할 수도 있습니다 . 또는 ... | grep 1반대 행동
acjay

2
@ acjohnson55 더 나은 : wc완전히 삭제하십시오 . 내 개정판을 참조하십시오. (종료 상태를 되돌리려면 Bash는 강타 연산자를 지원합니다. ! psql ...)
benesch

바로 지금, 이것을보고 있습니다
vol7ron

1
wc명령 을 삭제하라는 다른 제안 외에도을 사용 grep -qw <term>합니다. 0일치하는 항목이 있으면 쉘이 반환 됩니다 1. 그런 다음 $?반환 값을 포함하고이를 사용하여 다음에 수행 할 작업을 결정할 수 있습니다. 따라서이 wc경우에는 사용하지 않는 것이 좋습니다 . grep필요한 것을 할 것입니다.
Matt Friedman

귀하의 의견에 따라이 답변을 업데이트하려고했습니다. 모두 감사합니다.
kibibu

81

다음 쉘 코드가 나를 위해 작동하는 것 같습니다.

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
나는 당신이 외부 컷 그렙 wc와 물건을 중계하지 않기를 좋아합니다. db 존재를 확인합니다. 이것은 아마도 적어도 psql, 개미가 가장 작고 유일한 명령임을 의미합니다! 참으로 아주 좋은. 주제는 쉘 유형이나 명령 버전 또는 배포판에 대해서는 언급하지 않았습니다. 나는 그런 툴렛을 시스템 툴링에 중계하지 않았습니다. 그것은 년-나중에 문제로 연결
리카르도 Manfrin에게

1
@RiccardoManfrin에 동의합니다. 이보다 직접적인 솔루션 인 것 같습니다.
트래비스

postgres가 아닌 사용자로이 작업을 수행해야하는 경우 -U 사용자를 추가 할 수 있지만 연결할 데이터베이스를 나열해야합니다. 존재하지 않을 수 있으므로 항상 존재하는 postgres template1 데이터베이스를 사용할 수 있습니다. psql -U user -tAc "SELECT 1 FROM pg_database WHERE datname='DB_NAME'" template1
jan

cygwin에서 psql은 출력 ( '1 \ C-M')에 이상한 제어 문자를 추가하고 출력이 1로만 시작하는지 확인해야합니다.if [[ $(...) == 1* ]]
jan

28
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

10
첫 번째 제안은 매우 위험합니다. 무슨 일이 일어날 exact_dbname_test까요? 테스트하는 유일한 방법은 연결하는 것입니다.
wildplasser

6
이 답변은 강력하지 않습니다! 검색어가 다른 열에 나타나면 0이 아닌 숫자를 인쇄합니다 (반환되지 않음). 더 정확한 방법은 kibibu의 답변을 참조하십시오.
acjay 2016 년

1
"grep -w foo"는 "foo-bar"라는 데이터베이스가 존재할 때 잘못된 긍정을 줄 수 있습니다. 말할 것도없이 psql 출력 헤더에서 모든 단어를 찾을 수 있습니다.
Marius Gedminas

1
나는이 답변에 강력히 동의하지 않습니다. 논리 문에이 표현식을 사용하면 항상 참입니다. 다음 예제를 시험해 볼 수 있습니다. 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
모든 절단은 무엇입니까? 첫 번째 열만보고 있는지 확인하려면 regex :에 넣으십시오 psql -l | grep '^ exact_dbname\b'.이 코드는 찾지 못하면 종료 코드를 설정합니다.
Steve Bennett

21

postgresql을 처음 사용하지만 다음 명령은 데이터베이스가 있는지 확인하는 데 사용한 명령입니다.

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

9
로 단순화 할 수 있습니다 psql ${DB_NAME} -c ''.
Pedro Romano

2
데이터베이스가 존재하지만 연결할 수없는 경우 잘못된 음성 일 수 있지만 나에게 잘 보입니다 (아마도 가능합니까?)
Steve Bennett

7
@SteveBennett, 필요한 DB에 대한 권한이 없으면 존재하지 않습니다 :)
Viacheslav Dobromyslov

10

데이터베이스가 존재하지 않는 경우이 방법을 사용하여 데이터베이스를 작성할 수 있습니다.

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

9

간결하고 POSIX 호환 양식에 대한 다른 답변을 결합하고 있습니다.

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

true( 0) 의 반환은 존재한다는 의미입니다.

데이터베이스 이름에와 같은 비표준 문자가있을 수 있다고 생각되면 $약간 더 긴 접근 방식이 필요합니다.

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

-t-A옵션은 출력이 원시와 "표"또는 공백으로 채워 출력되지 않습니다 있는지 확인하십시오. 열 파이프 문자로 분리되는 |소위하거나, cut또는이 grep이를 인식한다. 첫 번째 열에는 데이터베이스 이름이 포함됩니다.

편집 : 부분 이름 일치를 방지하려면 -x를 사용하여 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 인과적인 산발적 사용의 경우 다른 답변을 선택하지만 일상적인 스크립트의 경우 더 깨끗하고 강력합니다. 주의 사항 : 사용자 'postgres'가 암호없이 cannect 할 수 있는지 확인하십시오.
leonbloy

예, 필요한 사용자 이름에 문제가 있습니다. OTOH : 연결 권한이없는 다른 역할을 사용하고 싶지 않습니다.
wildplasser

3

완성을 위해 문자열 절단 대신 정규식을 사용하는 다른 버전 :

psql -l | grep '^ exact_dbname\b'

예를 들어 :

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

를 사용하면 데이터베이스 이름에 단어가 아닌 문자를 포함 할 수 있으므로 일치하는 시도 도 일치 한다는 점에서 \b사용 grep -w하는 모든 답변과 동일한 문제 가 있습니다 . -foofoo-bar
phils

2

kibibu의 승인 된 답변 은 지정된 패턴을 단어 구성 요소로 포함하는 모든 이름 grep -w과 일치 한다는 점에서 결함이 있습니다.

즉, "foo"를 찾으면 "foo-backup"이 일치합니다.

Otheus의 답변 은 약간의 개선을 제공하며 짧은 버전은 대부분의 경우 올바르게 작동하지만 제공되는 두 변형 중 더 긴 부분은 일치하는 하위 문자열과 유사한 문제를 나타냅니다.

이 문제를 해결하기 위해 POSIX -x인수를 사용 하여 텍스트의 전체 줄만 일치 시킬 수 있습니다 .

Otheus의 답변을 바탕으로 새 버전은 다음과 같습니다.

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

결국, 나는 특정 데이터베이스에 대해 postgres에게 실제로 문의 하는 Nicolas Grilly의 대답 이 모든 사람의 최선의 접근 방법 이라고 말하고 싶습니다 .


2

환상적인 다른 솔루션은 psql이 호스트에 연결할 수없는 경우 시간이 초과되기 전에 1 분 이상 기다릴 수 있다는 사실을 놓치게됩니다. 그래서 나는이 솔루션을 좋아합니다. 시간 초과는 3 초로 설정됩니다.

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

공식 postgres Alpine Docker 이미지 의 개발 데이터베이스에 연결하기위한 것 입니다.

별도로, Rails를 사용하고 있고 아직 존재하지 않는 경우 (Docker 컨테이너를 시작할 때와 같이) 데이터베이스를 설정하려면 마이그레이션이 dem 등하므로 잘 작동합니다.

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

1

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

더 짧은 버전


0

나는 여전히 셸 프로그래밍에 익숙하지 않기 때문에 어떤 이유로 든 잘못 되었다면 투표하지 말고 너무 놀라지 마십시오.

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
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.