Reputation: 112
I am trying to pass value from string variable to complex bash command and I have problem with it. When I executing commands:
files=($(ls abc*))
for file in "${files[@]}"
do
scp $file [email protected]:~
ssh [email protected] 'PGPASSWORD="abcd" psql -h domain.com -U user -d dbb -f ~/$file'
ssh [email protected] 'rm ~/$file'
done
I get some errors. Only 'scp' is right executed but lines after them go fail. I am seeing "missing parameter for psql -f" and "file not found / cannot remove dictionary" What is problem with this code? How to pass string value to ssh commands?
Upvotes: 0
Views: 195
Reputation: 532053
Instead of copying each file to the remote host for execution, set up an SSH tunnel and run psql
locally, connecting to the remote db via the tunnel.
ssh -N -L 12345:domain.com:$DB_PORT [email protected] & ssh_pid=$!
files=(abc*)
for file in "${files[@]}"
do
psql -p 12345 -U user -d dbb -f "$file"
done
kill "$ssh_pid"
This has the added benefit of not exposing the database password, since you can simply type it manually or use a local .pgpass
file.
Note that the tunnel is only necessary if the remote database isn't configured to accept network connections.
Upvotes: 0
Reputation: 189749
Single quotes will prevent the remote shell from receiving your variable. Don't use ls
in scripts. Quote your variables. Use http://shellcheck.net/ before asking for human review.
for file in abc*
do
scp "$file" [email protected]:~
ssh [email protected] "PGPASSWORD='abcd' psql -h domain.com -U user -d dbb -f ~/'$file';
rm ~/'$file'"
done
The quoting here is slightly tricky, and won't work if your file names might contain e.g. literal single quotes. The double quotes cause the local shell to expand $file
; then the expanded value is in single quotes to prevent the remote ssh from manipulating it any further.
I took out the array because it didn't seem to serve any useful purpose. If you want an array, assign it simply with a wildcard:
files=(abc*)
Upvotes: 3
Reputation: 181159
What is problem with this code? How to pass string value to ssh commands?
One of the important distinctions between quoting with double quotes ("
) and quoting with single quotes ('
) is that the latter suppresses parameter expansion. You need to either move the $file
outside the quotes, or change to double-quote style. Additionally, however, you should properly quote the expansions of $file
, else you leave yourself open to breakage or even nasty surprises in the event of unusual file names, such as those containing spaces.
Moreover, the fact that you are formatting a command string that will be processed by a different shell adds some complication. The easiest way to be sure that you get the quoting right is to use bash's printf
builtin, whose %q
formatting option serves exactly the purpose of quoting an arbitrary string so that the result can be re-read as shell input to reproduce the same string. Overall, then, here's my recommendation for the loop:
for file in "${files[@]}"
do
scp "${file}" [email protected]:~
ssh [email protected] "PGPASSWORD='abcd' psql -h domain.com -U user -d dbb -f $(printf %q "~/${file}")"
ssh [email protected] "rm $(printf %q "~/${file}")"
done
Upvotes: 2