1

Unfortunatly psql -l uses linewraps

example see output and regard the "access" column

                                          List of databases
          Name           |   Owner    | Encoding |   Collate   |    Ctype    |   Access privileges
-------------------------+------------+----------+-------------+-------------+-----------------------
 firstdb                 | postgres   | UTF8     | de_DE.UTF-8 | de_DE.UTF-8 |
 secnddb                 | scnduser   | UTF8     | de_DE.UTF-8 | de_DE.UTF-8 |
 thrddb                  | scnduser   | UTF8     | de_DE.UTF-8 | de_DE.UTF-8 |
 postgres                | postgres   | UTF8     | de_DE.UTF-8 | de_DE.UTF-8 |
 template0               | postgres   | UTF8     | de_DE.UTF-8 | de_DE.UTF-8 | =c/postgres          +
                         |            |          |             |             | postgres=CTc/postgres
 template1               | postgres   | UTF8     | de_DE.UTF-8 | de_DE.UTF-8 | =c/postgres          +
                         |            |          |             |             | postgres=CTc/postgres
(6 rows)

hint even with some option, I can't get that gone:

$ psql -Atlqn
firstdb|postgres|UTF8|de_DE.UTF-8|de_DE.UTF-8|
secnddb|scnduser|UTF8|de_DE.UTF-8|de_DE.UTF-8|
thrddb|scnduser|UTF8|de_DE.UTF-8|de_DE.UTF-8|
postgres|postgres|UTF8|de_DE.UTF-8|de_DE.UTF-8|
template0|postgres|UTF8|de_DE.UTF-8|de_DE.UTF-8|=c/postgres
postgres=CTc/postgres
template1|postgres|UTF8|de_DE.UTF-8|de_DE.UTF-8|=c/postgres
postgres=CTc/postgres

Question Is there another way to get the list of databases in the same way \list prints it so I can use it in scripts for parsing with e.g. awk?

2 Answers 2

2

Interesting issue. You're being bitten by hard linewraps in ACL entries. Those aren't the only place they can appear btw, just the most common.

Use a null-byte recordsep

Rather than trying to avoid the newlines, why not use a different record separator? A null byte (\0) can be good; that's what the -0 option is for. It's only useful if your client can deal with null bytes, though; good for xargs -0, not good for lots of other stuff. The handy thing about a null byte is that it won't appear in psql's output otherwise so there's no risk of conflict. gawk does support null-separated records, though it's woefully underdocumented.

Try, e.g:

psql -Atlqn -0  | gawk -vRS=$'\0' '{ gsub("\n", " "); print }

which replaces newlines in database names (yes, they can appear there!), ACL entries, etc with a space.

Use a different recordsep

Alternately, use -R, e.g. -R '!' or -R '--SEPARATOR--' or whatever is easy for you to parse and not likely to appear in the output.

Query the catalogs yourself, escaping strings

Depending on the information you need, you can instead query the catalogs or information_schema directly, too. You'll still have to deal with funny chars, so you may want a regexp to escape any funny business.

Newlines and shell metacharacters

Beware that you still have to deal with unexpected newlines; consider what happens when some @#$@ does this:

 CREATE DATABASE "my
 database";

Yes, that's a legal database name. So are both of:

 CREATE DATABASE "$(rm -rf /gladthisisnotroot);";

 CREATE DATABASE "$(createuser -l -s my_haxxor -W top_secret)"

Yes, both are legal database names. Yes, that's really, really bad if you don't escape your shell metacharacters properly, you made the mistake of running your shell scripts as root or the postgres user, and they're not feeling nice.

Sign up to request clarification or add additional context in comments.

1 Comment

psql 9.1.1 seems not to support -0 it's supported from 9.2+ postgresql.org/docs/9.2/static/app-psql.html but thanks, yes this works: psql -Atlqn -F\| -R'~~SEP~~' | awk 'BEGIN{ FS="|"; RS="~~SEP~~";}{ print "nl:"$0 }'
2

All relevant data is in pg_database and pg_user see http://www.postgresql.org/docs/current/static/catalog-pg-database.html

select pg_database.datname,pg_user.usename,pg_encoding_to_char(pg_database.encoding),pg_database.datcollate,pg_database.datctype,pg_database.datacl from pg_database,pg_user WHERE pg_database.datdba = pg_user.usesysid;

on shell, wrapped in psql command:

psql -AStnq -c "select [...]"

returns correct formatted

template1|postgres|UTF8|de_DE.UTF-8|de_DE.UTF-8|{=c/postgres,postgres=CTc/postgres}
template0|postgres|UTF8|de_DE.UTF-8|de_DE.UTF-8|{=c/postgres,postgres=CTc/postgres}
postgres|postgres|UTF8|de_DE.UTF-8|de_DE.UTF-8|
firstdb|postgres|UTF8|de_DE.UTF-8|de_DE.UTF-8|
secnddb|scnduser|UTF8|de_DE.UTF-8|de_DE.UTF-8|
thrddb|scnduser|UTF8|de_DE.UTF-8|de_DE.UTF-8|

1 Comment

This won't protect you from a newline (or worse) in datname though.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.