PeterVandivier
I've been working on a PostgreSQL deployment and decided to use the following pattern.
1. separate service account for execution
2. single common "`release.sh`" master script
3. dot-source environment-specific data at the head of `release.sh`
A _very_ minified example follows:
```bash
$ cat release.sh
#!/usr/bin/env bash
. "./get-vars-$1.sh"
psql $PG_CONN \
-c 'select now(), current_user, session_user;' \
-f step-1.sql |& tee -a step-1.log
psql $PG_CONN \
-c 'select now(), current_user, session_user;' \
-f step-2.sql |& tee -a step-2.log
```
...where I have variables files for deploying to a docker instance as well as my localhost service...
```bash
$ cat get-vars-localhost.sh
#!/usr/bin/env bash
PG_URL=127.0.0.1
PG_PORT=5432
PG_DATABASE=postgres
PG_SERVICE_ACCOUNT=deploy
PG_CONN=" -h $PG_URL \
-d $PG_DATABASE \
-p $PG_PORT \
-U $PG_SERVICE_ACCOUNT "
```
...and the only difference between them is as follows.
```bash
$ diff get-vars-localhost.sh get-vars-docker.sh
4c4
< PG_PORT=5432
---
> PG_PORT=54320
```
During testing I noticed that tables were getting created with ownership assigned to the service account, so in the environments where it matters, I added `-c 'set role postgres; ' ` to the `$PG_CONN` variable. Sadly, this then threw an error...
```bash
$ psql $PG_CONN \
-c 'select now(), current_user, session_user;' \
-f step-1.sql | tee -a step-1.log
psql: warning: extra command-line argument "role" ignored
psql: warning: extra command-line argument "postgres;" ignored
psql: warning: extra command-line argument "'" ignored
Password for user deploy:
ERROR: unterminated quoted string at or near "'set"
LINE 1: 'set
^
now | current_user | session_user
-------------------------------+--------------+--------------
2020-05-04 13:03:13.857168+01 | deploy | deploy
(1 row)
psql:step-1.sql:1: NOTICE: table "foo" does not exist, skipping
DROP TABLE
CREATE TABLE
$
```
...and as you can seen the role assignment fails. I can work around this by either...
1. assigning the `set role` command in `release.sh`
2. wrapping the entire command in an `eval "psql $PG_CONN $(...)"` setup
...but I've been unable to properly escape the "`set role`" command inside the `$PG_CONN` variable directly.
> How do I escape space literals for this use case?
---
Please find the raw repro docs [at this link][1]
[1]: https://gist.github.com/petervandivier/125bb73d1be250369a4c27d3f13b53dc
Top Answer
Jack Douglas
You don't need to use `eval`, you can use [an array, instead of a simple text variable](https://superuser.com/a/360986):
---
```shell
PG_CONN="-d postgres -c 'select 1'"
psql "${PG_CONN}" postgres
psql: FATAL: database " postgres -c 'select 1'" does not exist
```
---
```shell
PG_CONN=(-d postgres -c 'select 1')
psql "${PG_CONN[@]}" postgres
Output format is wrapped.
Line style is unicode.
Border style is 2.
┌──────────┐
│ ?column? │
├──────────┤
│ 1 │
└──────────┘
```
> Putting commands (or parts of commands) into variables and then getting them back out intact is complicated. When the shell expands a variable on the command line, if the variable was in double-quotes it's not parsed; if it was not in quotes, spaces in it are parsed as argument breaks, but quotes and escape are not parsed. In either case, putting quotes in the variable's value does nothing useful.