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

Bre*_*wer 1 ssh bash subshell psql

试试这种方式:

#!/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"
Run Code Online (Sandbox Code Playgroud)

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

bash: -c: line 1: syntax error near unexpected token `2'
bash: -c: line 1: `2'
Run Code Online (Sandbox Code Playgroud)

另外,我试图:

myvals='1 2 3'
Run Code Online (Sandbox Code Playgroud)

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

Cha*_*ffy 5

如果它不是真正的阵列......

迭代一个字符串就像它是一个数组一样天生就是错误.不要这样做.也就是说,要生成一个安全转义(eval-safe)版本的值,请使用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'
Run Code Online (Sandbox Code Playgroud)

如果你实际上有阵列

#!/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'
Run Code Online (Sandbox Code Playgroud)

如果您不需要在本地存储价值

#!/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'")
Run Code Online (Sandbox Code Playgroud)

一般注意事项

  • echo "$i" >>values在循环中反复运行效率低下:每次运行该行时,它都会重新打开values文件.相反,>values 在整个循环上运行重定向; 这会在循环开始时将文件截断一次,并附加其中生成的所有值.
  • 不带引号的扩展通常是危险的.例如,如果foo='*',$foo则将替换为当前目录中的文件列表,但"$foo"将发出确切的内容 - *.类似地,即使直接传递echo,可以通过不带引号的扩展无意中损坏制表符,空白行和各种其他内容.
  • 您可以在同一个字符串中切换引用类型 - 因此,"$foo"'$foo'是一个字符串,其第一部分用名为变量的值替换,foo第二部分是精确字符串$foo.