我想在本地创建一个函数echo_a
,并通过ssh将其传递给远程shell,此处为typeset -f
。问题是函数无法访问局部变量。
export a=1
echo_a() {
echo a: $a
}
bash <<EOF
$(typeset -f echo_a)
echo local heredoc:
echo_a
echo
echo local raw heredoc:
echo a: $a
echo
EOF
ssh localhost bash <<EOF
$(typeset -f echo_a)
echo remote heredoc:
echo_a
echo
echo remote raw heredoc:
echo a: $a
echo
EOF
假设ssh连接是自动的,运行上面的脚本会给我输出:
local heredoc:
a: 1
local raw heredoc:
a: 1
remote heredoc:
a:
remote raw heredoc:
a: 1
看看“远程heredoc”a
是如何空的?我该怎么办才能获得1
?
我测试过在任何地方添加引号和反斜杠都没有成功。
我错过了什么?除typeset
以外的其他内容会使这项工作吗?
答案 0 :(得分:0)
感谢@Guy提示,确实是因为默认情况下ssh禁用发送环境变量。就我而言,不需要更改服务器的设置。
希望我们可以使用compgen
,eval
和declare
进行攻击。
首先,我们通常会识别添加的变量。如果在被调用函数内创建变量也可以工作。使用compgen
很简洁,因为我们不需要显式地export
变量。
数组差异代码来自https://stackoverflow.com/a/2315459/1013628和来自https://stackoverflow.com/a/16337687/1013628的compgen
技巧。
# Store in env_before all variables created at this point
IFS=$'\n' read -rd '' -a env_before <<<"$(compgen -v)"
a=1
# Store in env_after all variables created at this point
IFS=$'\n' read -rd '' -a env_after <<<"$(compgen -v)"
# Store in env_added the diff betwen env_after and env_before
env_added=()
for i in "${env_after[@]}"; do
skip=
for j in "${env_before[@]}"; do
[[ $i == $j ]] && { skip=1; break; }
done
if [[ $i == "env_before" || $i == "PIPESTATUS" ]]; then
skip=1
fi
[[ -n $skip ]] || env_added+=("$i")
done
echo_a() {
echo a: $a
}
env_added
现在拥有两个compgen
调用之间添加变量的所有名称数组。
$ echo "${env_added[@]}"
a
我还会过滤出变量env_before
和PIPESTATUS
,因为它们是由bash自动添加的。
然后,在heredocs中,我们添加eval $(declare -p "${env_added[@]}")
。
declare -p VAR [VAR ...]
为每个VAR
打印变量名称,后跟=
,后跟其值:
$ a = 1
$ b = 2
$ declare -p a b
declare -- a=1
declare -- b=2
eval实际上是评估declare
行。其余代码如下:
bash <<EOF
# Eval the variables computed earlier
eval $(declare -p "${env_added[@]}")
$(typeset -f echo_a)
echo local heredoc:
echo_a
echo
echo local raw heredoc:
echo a: $a
echo
EOF
ssh rpi_301 bash <<EOF
# Eval the variables computed earlier
eval $(declare -p "${env_added[@]}")
$(typeset -f echo_a)
echo remote heredoc:
echo_a
echo
echo remote raw heredoc:
echo a: $a
echo
EOF
最后,运行修改过的脚本会给我想要的行为:
local heredoc:
a: 1
local raw heredoc:
a: 1
remote heredoc:
a: 1
remote raw heredoc:
a: 1