Linux
在遠端伺服器上執行本地功能程式碼
我正在更新大約 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.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 出現故障,我們將無法使用我們的腳本- 我可以在執行腳本之前 scp
shared.sh
到伺服器。這會起作用,但可能會有點慢,如果shared.sh
依賴於其他腳本,我們也必須複製該文件- 我可以用它
declare -f
來提取我的函式的程式碼,但我想不出一個很好的方法來將它們改組到遠端伺服器。函式依賴也可能導致問題。關於我能找到的最乾淨的解決方案是使用Process Substitution內聯執行共享庫:
#!/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
)- 有沒有更好的方法來解決這個問題?
在這裡回答我自己的問題。
我們現在有一個這樣的函式:
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中並不感到興奮。只要它保留幾個聲明,然後是一個簡單的函式呼叫,我認為就可以了。
所以我用來完成這項任務的是一種不同的方法。首先,我創建了一個名為
remotely
1的執行腳本:#!/bin/bash # Usage: # Put this thing as a shebang into your scripts # i.e.: # # #!/bin/remotely user@your-server.com # # 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 user@your-server.com echo "hello world from ${hostname}"
也可以調整它以支持使用類似
gnu-parallel
.