bashsshpsqlsubshell

How do I pass subshell results (array) to an SSH command?


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?


Solution

  • 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