【问题标题】:Passing variables to SSH [duplicate]将变量传递给 SSH [重复]
【发布时间】:2021-03-22 22:19:12
【问题描述】:

以下代码循环遍历数组中的状态,并通过 ssh 将状态传递给服务器 -

STATES="NY CO"

arr_states=(${STATES//' /'/ })

for i in "${arr_states[@]}"; do
  state=$i
  
  ssh -o SendEnv=state jenkins@server sh -s << 'EOF'
  sudo su
  cd /home/jenkins/report

  psql -d db -c "$(sed 's/state_name/'"$state"'/' county.sql)" -U user

  echo $state

EOF

done

上面echo $state的输出即使我传递NY也是一个空字符串。

当我将'EOF' 更改为EOF 时,echo $state 的输出是我传递的字符串 (NY)。但随后它说,文件county.sql 不存在。

如何让它识别我传递的变量和我试图运行的远程文件。

【问题讨论】:

  • 真的需要向我们展示 STATES 里面有什么。
  • 这绝对不正确 - 尝试将状态设置为 arr_states=( CO NY ) - 给出您期望的输出类型(其中 $state 有一个值)。
  • 是否有令人信服的理由使用sh -s 而不是bash -s?许多 bash 以编程方式生成可安全执行的代码的机制只有在接收 shell 也是 bash 时才有效。

标签: shell ssh


【解决方案1】:

作为一种不需要您对代码进行任何手动转义的方法(这通常会成为维护的噩梦,因为这意味着每当您修改预期运行的位置时都需要更改代码)——考虑定义一个函数,并使用declare -f 要求shell 生成将为您输出该函数的代码。

变量也可以使用declare -p。因此,通过远程代码传递一个函数,以及远程代码需要以这种方式操作的变量:

#!/usr/bin/env bash

# This is run on the remote server _as root_ (behind sudo su)
remotePostEscalationFunc() {
  cd /home/jenkins/report || return
  if psql -d db -U user -c "$(sed -e "s/state_name/${state}/" county.sql)"; then
    echo "Success processing $state" >&2
  else
    rc=$?
    echo "Failure processing $state" >&2
    return "$rc"
  fi
}

# This is run on the remote server as the jenkins user (before sudo).
remoteFunc() {
  sudo su -c "$(declare -p state); $(declare -f remotePostEscalationFunc); remotePostEscalationFunc"
}

# Everything below here is run locally.

arr_states=( NY CO )

for state in "${arr_states[@]}"; do
  ssh jenkins@server 'bash -s' <<EOF
$(declare -f remoteFunc remotePostEscalationFunc); $(declare -p state); remoteFunc
EOF
done

【讨论】:

  • 写的真好!我遇到的唯一问题是 - 当我将 psql -d db -U user -c "COPY public.tab (npi, va_pct, commercial_pct, other_pct) FROM '/tmp/data.tab' DELIMITER ',' CSV HEADER" 语句添加到 remoteFunc 时,出现语法错误。
  • 如果我们将需要提权的东西拆分成一个单独的函数,事情会变得容易一些,这样shell就可以为我们做更多的转义,而不是我们自己做。大约一个小时后,我会坐在我的办公桌前,然后试一试。
  • 谢谢!上面的语句是我们需要远程shell来做的事情。
  • 查看编辑——我没有添加您的更改,因为它不在问题中,但是您在 remotePostEscalationFunc 的定义中写的任何内容都可以使用您可以使用的完全相同的语法在远程系统的命令行上,无需更改引用/转义/等。
【解决方案2】:

'EOF'EOF 的更改几乎是正确的。您只是在$(sed 之前缺少一个反斜杠 (\)。所以以下应该工作:

arr_states=(${STATES//' /'/ })

for i in "${arr_states[@]}"; do
  state=$i
  
  ssh -o SendEnv=state jenkins@server sh -s << EOF
  sudo su
  cd /home/jenkins/report

  psql -d db -c "\$(sed 's/state_name/'"$state"'/' county.sql)" -U user

  echo $state

EOF

done

【讨论】:

  • 这解决了我的问题。你能解释一下反斜杠的作用以及它解决问题的原因吗?
  • @Aaron,反斜杠会在代码到达远程 shell 之前阻止本地 shell 运行扩展。
猜你喜欢
  • 2013-03-28
  • 2014-01-11
  • 2016-02-23
  • 2013-01-28
  • 2012-09-24
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多