问题
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?
回答1:
If It's Not Really An Array...
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'
If You Actually Had An Array
#!/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'
If You Don't Need To Store The Value Locally In The First Place
#!/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'")
General Notes
- Running
echo "$i" >>values
over and over in a loop is inefficient: Every time the line is run, it re-opens thevalues
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. - Unquoted expansions are generally dangerous. For example, if
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 toecho
. - You can switch quoting types in the same string -- thus,
"$foo"'$foo'
is one string, the first part of which is replaced with the value of the variable namedfoo
, and the second component of which is the exact string$foo
.
回答2:
You can send the output as a file:
#!/bin/bash
psql -d mydb -c "select id from table1 where 't'" > /tmp/values
scp values user1@host1.domain.tld:/tmp/
or pipe it to the remote host:
psql -d mydb -c "select id from table1 where 't'" | \
ssh user1@host1.domain.tld 'while read line; do echo $line; done'
来源:https://stackoverflow.com/questions/47490844/how-do-i-pass-subshell-results-array-to-an-ssh-command