我正在更新大约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
一些脚本使用共享函数和环境variables。 我可以使用ssh SendEnv选项传递环境variables,但我无法弄清楚在远程运行时使共享函数可用的好方法。
./shared.sh
# 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到服务器。 这将工作,但可能会有点慢,如果shared.sh取决于其他一些脚本,我们将不得不复制该文件 declare -f来提取我的函数的代码,但是我找不到一个很好的方法来将它们转移到远程服务器上。 函数依赖也可能导致问题。 关于我能find的最干净的解决scheme是使用进程replace内联运行共享库:
#!/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 ) 所以我一直用来完成这个任务是一个不同的方法。 首先我创build了一个remotely调用的脚本1 :
#!/bin/bash # Usage: # Put this thing as a shebang into your scripts # ie: # # #!/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类的东西来支持多个主机。
在这里回答我自己的问题。
我们现在有这样一个function:
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
它远非完美,但比我们所拥有的还要难看:)
先前的回答:
在上面的脚本中很难遵循控制stream程,我想我正在解决这样的问题:
#!/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中我并不兴奋。 只要它仍然是一些声明,然后是一个简单的函数调用,我认为没关系。