如何将子 shell 结果(数组)传递给 SSH 命令?

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

这样尝试:

#!/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"

只要psql returns只有一个值,就可以正常工作。但如果它有多个值,我会收到这样的回复:

bash: -c: line 1: syntax error near unexpected token `2'
bash: -c: line 1: `2'

此外,我尝试过:

myvals='1 2 3'

然后它工作正常:值 1 2 3 附加到远程主机上的 "values" 文件;没有错误信息。 如果我尝试另一个子 shell 命令,例如 myvals=ls /bin,错误会再次出现。 很明显 $myvals 已经在本地主机上进行了评估,但是是什么让子 shell 结果如此不同?

如果它不是真正的数组...

像数组一样遍历字符串本身就是错误的。 Don't do it. 也就是说,要生成您的值的安全转义(eval-安全)版本,请使用 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 一遍又一遍地循环是低效的:每次行是 运行,它 重新打开 values 文件。相反,运行 重定向 >values 遍及整个循环 ;此 t运行 在循环开始时恰好对文件进行一次分类,并附加其中生成的所有值。
  • 不加引号的扩展通常是危险的。例如,如果 foo='*',则 $foo 将替换为当前目录中的文件列表,但 "$foo" 将发出确切的内容 -- *。同样,制表符、空格 运行s 和各种其他内容可能会被未引用的扩展无意中损坏, 即使直接传递给 echo.
  • 您可以在同一字符串中切换引号类型——因此,"$foo"'$foo' 是一个字符串,其第一部分替换为名为 foo 的变量的值,第二部分其中的组成部分是 exact 字符串 $foo.

您可以将输出作为文件发送:

#!/bin/bash
psql -d mydb -c "select id from table1 where 't'" > /tmp/values
scp values user1@host1.domain.tld:/tmp/

或将其通过管道传输到远程主机:

psql -d mydb -c "select id from table1 where 't'" | \
  ssh user1@host1.domain.tld 'while read line; do echo $line; done'