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.