如何将子 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 只返回一个值,它就可以正常工作.但是如果它有几个值,我会收到这个回复:
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'
另外,我尝试:
myvals='1 2 3'
然后它工作正常:值 1 2 3 被附加到远程主机上的值"文件;没有错误信息.如果我尝试另一个子 shell 命令,例如 myvals=ls/bin
,错误会再次出现.很明显 $myvals 已经在本地主机上进行了评估,但是是什么让 subshell 结果如此不同?
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?
推荐答案
如果它不是真正的数组...
将字符串当作数组进行迭代是天生的错误.不要这样做. 也就是说,要生成安全转义(eval
-safe) 版本的值,使用 printf %q
.
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'
<小时>
如果你真的有一个数组
#!/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
;这只会在循环开始时截断文件一次,并附加其中生成的所有值. - 未加引号的扩展通常是危险的.例如,如果
foo='*'
,则$foo
将替换为当前目录中的文件列表,但"$foo"
将发出确切的内容——*
.同样,制表符、空格符和各种其他内容可能会被不带引号的扩展无意中损坏,即使直接传递给echo
. - 您可以在同一个字符串中切换引用类型——因此,
"$foo"'$foo'
是一个字符串,其中的第一部分替换为名为 <的变量的值code>foo,其第二部分是 exact 字符串$foo
. - Running
echo "$i" >>values
over and over in a loop is inefficient: Every time the line is run, it re-opens thevalues
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 toecho
. - 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 namedfoo
, and the second component of which is the exact string$foo
.
General Notes
这篇关于如何将子 shell 结果(数组)传递给 SSH 命令?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!