如何将子 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'
这样尝试:
#!/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'