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

时间:2017-11-25 21:50:50

标签: bash ssh psql subshell

以这种方式尝试:

#!/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只返回一个值,它就可以正常工作。但如果有几个值,我收到这个回复:

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

另外,我试图:

myvals='1 2 3'

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

2 个答案:

答案 0 :(得分:5)

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

迭代一个字符串就像它是一个数组一样天生就是错误的。 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 ;这会在循环开始时截断文件一次,并附加其中生成的所有值。
  • 不带引号的扩展通常很危险。例如,如果foo='*',则$foo将替换为当前目录中的文件列表,但"$foo"将发出确切的内容 - *。类似地,即使直接传递到echo ,也可以通过不带引号的扩展无意中损坏制表符,空白行和其他各种内容。
  • 您可以在同一个字符串中切换引用类型 - 因此,"$foo"'$foo'是一个字符串,其第一部分被替换为名为foo的变量的值,而第二部分是这是完全字符串$foo

答案 1 :(得分:0)

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

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