Trying it this way:
#!/bin/bash
myvals=`psql -d mydb -c "select id from table1 where 't'"`
ssh user1@host1.domain.tld "for i in $myvals; do echo \$i >> values; done"
As long as psql returns just one value, it works fine. But if its several values, I receive this response:
bash: -c: line 1: syntax error near unexpected token `2'
bash: -c: line 1: `2'
Also, I tried to:
myvals='1 2 3'
And then it works fine: the values 1 2 3 are appended to the "values" file on the remote host; no error mesages.
If I try another subshell command, such as myvals=ls /bin
, errors reappear.
It's clear that $myvals is evaluated on the local host already but what makes the subshell results so different?
Iterating over a string as if it were an array is innately buggy. Don't do it. That said, to generate a safely-escaped (eval
-safe) version of your value, use printf %q
.
#!/bin/bash
myvals=`psql -d mydb -c "select id from table1 where 't'"`
printf -v myvals_q %q "$myvals"
ssh user1@host1.domain.tld \
"myvals=$myvals_q;"' for i in $myvals; do echo "$i"; done >>values'
#!/bin/bash
readarray -t myvals < <(psql -d mydb -c "select id from table1 where 't'")
printf -v myvals_q '%q ' "${myvals[@]}"
ssh user1@host1.domain.tld \
"myvals=( $myvals_q );"' for i in "${myvals[@]}"; do echo "$i"; done >>values'
#!/bin/bash
ssh user1@host1.domain.tld \
'while read -r i; do echo "$i"; done >>values' \
< <(psql -d mydb -c "select id from table1 where 't'")
echo "$i" >>values
over and over in a loop is inefficient: Every time the line is run, it re-opens the values
file. Instead, run the redirection >values
over the whole loop; this truncates the file exactly once, at the loop's start, and appends all values generated therein.foo='*'
, then $foo
will be replaced with a list of files in the current directory, but "$foo"
will emit the exact contents -- *
. Similarly, tabs, whitespace runs, and various other contents can be unintentionally damaged by unquoted expansion, even when passing directly to echo
."$foo"'$foo'
is one string, the first part of which is replaced with the value of the variable named foo
, and the second component of which is the exact string $foo
.