I'm trying to run pg_dump
in a docker container, in a bash function, but I'm getting an error can't create : nonexistent directory
. The dir does exist, so I suspect that the output redirection (>) is trying to run on the host system when running inside the function. When I run the command outside of the bash function it works.
Note that the psql container has the directory /var/lib/postgresql/backups/
mapped to /usr/share/postgresql/backups/
on the host.
The command that works is,
docker exec -it psql sh -c 'pg_dump -U $PG_USER MY_TABLE > /var/lib/postgresql/backups/my_table.sql
The function that is not working
# @param $1 -- the name of the table to export
# @param $2 -- the filename to export the table to
function backup_table() {
local table_name="$1"
local output_path="/var/lib/postgresql/backups/$2"
docker exec -it psql sh -c 'pg_dump -U "$PG_USER" $table_name > $output_path'
}
backup_table MY_TABLE my_table.sql
The redirection is properly happening inside the container -- but output_path
isn't being passed there.
Assuming PG_USER
is defined inside the container:
backup_table() { # POSIX function syntax
local table_name output_path cmd # declare all our locals at once
table_name="$1"
output_path="/var/lib/postgresql/backups/$2"
# Bash extension, compatible through older releases: substitute
# escaped values in place of %q placeholders into $cmd
printf -v cmd 'pg_dump -U "$PG_USER" %q >%q' "$table_name" "$output_path"
docker exec -it psql bash -c "$cmd"
}
backup_table MY_TABLE my_table.sql
Note:
function backup_table {
and POSIX backup_table() {
previously in use.printf %q
to escape variables before substituting them into shell syntax, to ensure that the remote shell parses the content back to their original values.bash -c
instead of sh -c
, because printf %q
only guarantees compatibility with the same shell (so ksh's printf %q
generates code that ksh is guaranteed to parse, etc) in corner cases. (It's possible to write a helper that uses the Python shlex
module if you need to generate escapings compatible with all POSIX shells, but arguably out-of-scope here).local var=$(somecommand)
returns the exit status of local
, not that of somecommand
; being in the habit of separating local var
from actual assignment to var
avoids the pitfall.If you only need to support bash 5.0 or newer, you could replace the printf command with:
cmd='pg_dump -U "$PG_USER" '"${table_name@Q}"' >'"${output_path@Q}"