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);
}