diff --git a/doc/src/sgml/ref/psql-ref.sgml b/doc/src/sgml/ref/psql-ref.sgml index 969548f..6719135 100644 --- a/doc/src/sgml/ref/psql-ref.sgml +++ b/doc/src/sgml/ref/psql-ref.sgml @@ -1971,7 +1971,8 @@ lo_import 152801 Sets the output format to one of unaligned, aligned, wrapped, html, - latex, or troff-ms. + latex, troff-ms or + shell. Unique abbreviations are allowed. (That would mean one letter is enough.) @@ -1996,6 +1997,24 @@ lo_import 152801 if the total width needed for column headers exceeds the target. + shell format is designed for using in shell scripts. + +( psql -t -P format=shell postgres <<EOF +SELECT d.datname as "Name", + pg_catalog.pg_get_userbyid(d.datdba) as "Owner", + pg_catalog.pg_encoding_to_char(d.encoding) as "Encoding", + d.datcollate as "Collate", + d.datctype as "Ctype", + pg_catalog.array_to_string(d.datacl, E'\n') AS "Access privileges" +FROM pg_catalog.pg_database d +ORDER BY 1; +EOF +) | while read dbname owner encoding collate ctype priv; + do + echo "DBNAME=$dbname OWNER=$owner PRIVILEGES=$priv"; + done; + + The html, latex, and troff-ms formats put out tables that are intended to diff --git a/src/bin/psql/command.c b/src/bin/psql/command.c index 7f91ff9..c3313ec 100644 --- a/src/bin/psql/command.c +++ b/src/bin/psql/command.c @@ -2148,6 +2148,9 @@ _align2string(enum printFormat in) case PRINT_TROFF_MS: return "troff-ms"; break; + case PRINT_SHELL: + return "shell"; + break; } return "unknown"; } @@ -2180,6 +2183,8 @@ do_pset(const char *param, const char *value, printQueryOpt *popt, bool quiet) popt->topt.format = PRINT_LATEX; else if (pg_strncasecmp("troff-ms", value, vallen) == 0) popt->topt.format = PRINT_TROFF_MS; + else if (pg_strncasecmp("shell", value, vallen) == 0) + popt->topt.format = PRINT_SHELL; else { psql_error("\\pset: allowed formats are unaligned, aligned, wrapped, html, latex, troff-ms\n"); diff --git a/src/bin/psql/print.c b/src/bin/psql/print.c index c431f6a..f375811 100644 --- a/src/bin/psql/print.c +++ b/src/bin/psql/print.c @@ -2037,6 +2037,125 @@ print_troff_ms_vertical(const printTableContent *cont, FILE *fout) } } +/********************/ +/* Shell */ +/********************/ + +static void +shell_escaped_print(const char *in, FILE *fout) +{ + const char *p; + + for (p = in; *p; p++) + switch (*p) + { + case '\n': + fputs("\\\\n", fout); + break; + case '\\': + case '\'': + case '\"': + case '[': + case ']': + case ' ': + fputc('\\', fout); + default: + fputc(*p, fout); + } +} + + +static void +print_shell_text(const printTableContent *cont, FILE *fout) +{ + bool opt_tuples_only = cont->opt->tuples_only; + unsigned int i; + const char *const * ptr; + + if (cancel_pressed) + return; + + if (cont->opt->start_table) + { + /* print headers */ + if (!opt_tuples_only) + { + for (i = 0, ptr = cont->headers; i < cont->ncolumns; i++, ptr++) + { + if (i != 0) + fputc(' ', fout); + shell_escaped_print(*ptr, fout); + } + fputc('\n', fout); + } + } + + /* print cells */ + for (i = 0, ptr = cont->cells; *ptr; i++, ptr++) + { + shell_escaped_print(*ptr, fout); + + if ((i + 1) % cont->ncolumns == 0) + { + fputc('\n', fout); + if (cancel_pressed) + break; + } + else + fputc(' ', fout); + } +} + + +static void +print_shell_vertical(const printTableContent *cont, FILE *fout) +{ + bool opt_tuples_only = cont->opt->tuples_only; + unsigned int i; + const char *const * ptr; + bool is_first = true; + + if (cancel_pressed) + return; + + if (cont->opt->start_table) + { + /* print headers */ + if (!opt_tuples_only) + { + fputs("( c l )\n", fout); + } + } + + /* print records */ + for (i = 0, ptr = cont->cells; *ptr; i++, ptr++) + { + /* new record */ + if (i % cont->ncolumns == 0) + { + if (cancel_pressed) + break; + + if (!is_first) + fputs(")\n( ", fout); + else + { + fputs("( ", fout); + is_first = false; + } + } + + fputc('[', fout); + shell_escaped_print(cont->headers[i % cont->ncolumns], fout); + fputs("]=", fout); + shell_escaped_print(*ptr, fout); + fputc(' ', fout); + } + + if (!is_first) + fputs(")\n", fout); +} + /********************************/ /* Public functions */ @@ -2431,6 +2550,12 @@ printTable(const printTableContent *cont, FILE *fout, FILE *flog) else print_troff_ms_text(cont, fout); break; + case PRINT_SHELL: + if (cont->opt->expanded == 1) + print_shell_vertical(cont, fout); + else + print_shell_text(cont, fout); + break; default: fprintf(stderr, _("invalid output format (internal error): %d"), cont->opt->format); diff --git a/src/bin/psql/print.h b/src/bin/psql/print.h index 25adfc5..0c61fc5 100644 --- a/src/bin/psql/print.h +++ b/src/bin/psql/print.h @@ -19,7 +19,8 @@ enum printFormat PRINT_WRAPPED, PRINT_HTML, PRINT_LATEX, - PRINT_TROFF_MS + PRINT_TROFF_MS, + PRINT_SHELL /* add your favourite output format here ... */ }; diff --git a/src/bin/psql/tab-complete.c b/src/bin/psql/tab-complete.c index a50e735..5bbe201 100644 --- a/src/bin/psql/tab-complete.c +++ b/src/bin/psql/tab-complete.c @@ -3007,7 +3007,7 @@ psql_completion(char *text, int start, int end) { static const char *const my_list[] = {"unaligned", "aligned", "wrapped", "html", "latex", - "troff-ms", NULL}; + "troff-ms", "shell", NULL}; COMPLETE_WITH_LIST_CS(my_list); }