我正在更新大约 20 个 bash 脚本,这些脚本执行各种服务器端操作任务、检查状态/发送报告等。在某些环境中,这些脚本将在本地运行,在其他环境中,它们需要远程运行。脚本应该检测它们是否需要远程运行或本地运行,并“做正确的事情”
#!/bin/bash
# Generate the foo report
execute_host=appdev7
if [[ "$execute_host" != "$(hostname)" ]]; then
# ssh-agent will provide passwordless logon
ssh "$execute_host" < $0
else
# run report
echo "Report"
fi
一些脚本使用共享函数和环境变量。我可以使用 ssh SendEnv 选项传递环境变量,但我找不到一种在远程运行时使共享函数可用的好方法。
复制代码
# Shared functions and variables
export report_host="appdev7"
function run_report() {
# run report
echo 'Report'
}
。/例子
#!/bin/bash
# Generate the foo report
[[ -f shared ]] && source ./shared.sh
export execute_host="$report_host"
if [[ "$execute_host" != "$(hostname)" ]]; then
# ssh-agent will provide passwordless logon
ssh -o SendEnv='report_host' "$execute_host" < $0
else
# This doesn't work when the script is run remotely
run_report
fi
- 我可以将其放置
shared.sh
在我们所有的主机上,但我必须以某种方式保持文件同步,而这在某些时候不可避免地会出现问题。 - 我可以将其放置
shared.sh
在 NFS 共享上,但如果 NFS 发生故障,我们将无法使用脚本 - 我可以
shared.sh
在运行脚本之前 scp 到服务器。这可行,但可能有点慢,而且如果shared.sh
依赖于其他脚本,我们还必须复制该文件 - 我可以使用
declare -f
来提取函数代码,但我不知道如何将它们转移到远程服务器。函数依赖性也可能导致问题。
我能找到的最干净的解决方案是使用内联运行共享库流程替代:
#!/bin/bash
# Generate the foo report
# source the shared code/vars if we're running locally
[[ -f shared.sh ]] && source shared.sh
execute_host="$report_host"
if [[ "$execute_host" != "$(hostname)" ]]; then
# ssh-agent will provide passwordless logon
# Note that we source the shared library in-line with the script
ssh -T "$execute_host" < <(cat shared.sh $0)
else
run_report
fi
我的问题是:
- 这种方法有什么问题吗?
- 您能找到避免在多个地方引用共享库的方法吗?
- 有什么方法可以解决
shared.sh
? 中的依赖关系(例如,如果shared.sh
依赖于shared2.sh
) - 有没有更好的方法来解决此问题?
答案1
因此,我使用了一种不同的方法来完成这项任务。首先,我创建了一个名为remotely
1 的执行脚本:
#!/bin/bash
# Usage:
# Put this thing as a shebang into your scripts
# i.e.:
#
# #!/bin/remotely [email protected]
#
# echo "hello world from ${hostname}"
#
login=$1
script=$2
args=${@#$1}
args=${args#$2}
tar cz $script | ssh $login "tar xz && bash --login $script $args"
然后在应该远程执行的脚本中使用它:
#!/bin/remotely [email protected]
echo "hello world from ${hostname}"
它还可以通过使用类似的东西来调整以支持多个主机gnu-parallel
。
答案2
在这里回答我自己的问题。
我们现在有这样的函数:
function remote::run() {
# usage: remote::run "host" "includes" "commands"
# where "includes" is a list of functions to export to
# the remote host
[[ -n "$2" ]] && includes="$(declare -f $2);"
ssh -T $1 "$includes $3"
}
这使我们能够做类似的事情(人为的例子):
function status::report() {
date
host $(hostname)
}
remote::run $REMOTE_HOSTNAME status::report 'echo status report:; status::report' > out
虽然远非完美,但比起我们之前的要好一些:)
上一个答案:
很难遵循上述脚本中的控制流,我想我可以决定采用如下方法:
#!/bin/bash
# Generate the foo report
# source the shared code/vars if we're running locally
[[ -f shared.sh ]] && source shared.sh
if [[ "$report_host" != "$(hostname)" ]]; then
# ssh-agent will provide passwordless logon
runner="ssh -T -o SendEnv=report_host $report_host"
else
# run report locally
runner="bash"
fi
report="$($runner << EOF
$(declare -f run_report)
run_report
EOF
)"
echo "$report" | mail -s "daily foo report" root
我并不赞成将远程代码放在 heredoc 中。只要它仍然是几个声明,然后是一个简单的函数调用,我认为就可以了。