1

I have Postgres running in a docker container on a remote host. I'm attempting to ssh to that remote host, and use a heredoc to pass a script to that shell. In that script, I attempt to execute a psql query against the postgres database that resides in the container on that host, and assign the output to a variable. I'm sorry, I know that's a bit convoluted, but maybe some code will be more coherent (nor not)

If I run this, I get nothing out of my "echo" of $dbVersion... in fact, due to some other experimentation, I'm fairly convinced it never gets to the "echo" line at all, but for the life of me I don't know why, because...

ssh root@$serverIP13 <<EOF
postgresId=\$(docker ps | grep 'postgres_db' | awk '{print \$1}')
dbVersion=\$(docker exec -i \$postgresId psql -X -A -d myDb  -U myUser -t -c "SELECT Max(Version) FROM DbVersion;")
echo \$dbVersion
EOF

...after turning and twisting my code this way and that... I finally found a way that works, and I get a successful "echo" of my version number. I'm quite new to bash, so I'm hoping someone out there can discern this mystery for me and help me understand a bit better how bash works in this regard, and why the below succeeds, and the above fails.

ssh root@$serverIP13 <<EOF
postgresId=\$(docker ps | grep 'postgres_db' | awk '{print \$1}')
dbVersion=\$(echo "psql -X -A -d myDb -U myUser -t -c 'SELECT Max(Version) FROM DbVersion;'" | docker exec -i \$postgresId bash)
echo \$dbVersion
EOF
  • Is the database listening on a port accessible from the network? It'd be much easier to run `psql -h "$serverIP13" ...` from your local system if so, skipping both the `ssh` and `docker exec` steps. – David Maze Aug 11 '20 at 10:46
  • I always appreciate folks with common sense! The only port I have open is 22, as I'm trying to constrain my exposure, but... I'm going to add this to my backlog of things to try to do in a future sprint because... it is the simpler solution, and simpler solutions are less likely to break. Thank you for the suggestion. – JesusIsMyDriver.dll Aug 11 '20 at 21:21
  • 1
    `ssh -L 5432:localhost:5432 root@$serverIP13` to port forward over the ssh connection could help too. That's a couple of network hops, but would let you use a local `psql` client. – David Maze Aug 11 '20 at 23:56

2 Answers2

2

The normal way to get a docker exec -i output is to call for docker to run a shell (which, in turn, runs your command.
See "Bash / Docker exec: file redirection from inside a container" (I mentioned in 2015)

dbVersion=\$(docker exec -i sh -c '\$postgresId psql -X -A -d myDb  -U myUser -t -c "SELECT Max(Version) FROM DbVersion;"')
VonC
  • 1,262,500
  • 529
  • 4,410
  • 5,250
1

Following script worked without invoking bash :

ssh root@$serverIP13 << 'EOF'
postgresId=$(docker ps | grep 'postgres_db' | awk '{print $1}')
dbVersion=$(docker exec $postgresId psql -X -A -d postgres -U postgres -c "select current_database()")
echo $dbVersion
EOF

I use 'EOF' to avoid having to escape.

To pass local values to remote :

ssh root@$serverIP13 /bin/bash -s 1 2 3 << 'EOF'
echo $1 $2 $3
EOF

You should not use -i if you put docker exec in $(...)

Philippe
  • 20,025
  • 2
  • 23
  • 32
  • Thank you for this. I often have variables coming into my script that need to be expanded, but in this case, I do not so good call. That said... is there a way to force variable expansion if you use a quoted 'EOF'? – JesusIsMyDriver.dll Aug 11 '20 at 21:23
  • No, then you have to use an unescaped `EOF` and quote everything else like in your original attempt. – tripleee Aug 12 '20 at 06:58