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

三世轮回 提交于 2020-01-23 17:15:25

问题


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 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.
  • 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 to echo.
  • 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 named foo, 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

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!