在遠端主機上使用本機輸入檔案執行本機腳本

在遠端主機上使用本機輸入檔案執行本機腳本

我有一個本地腳本,想在多個遠端伺服器上運行。我使用的命令語法是:

ssh <remote_server> "bash -s" < ./local_script.sh

這工作得很好,甚至可以讓我將參數傳遞給本地腳本.sh。但是,我真的很想將輸入檔傳遞給它,如下所示:

local_script.sh < local_file.txt

結合這兩個語句可以得到:

ssh <remote_server> "bash -s" < ./local_script.sh < local_file.txt

當我運行這個時,我得到

bash: line 1: FOO: command not found
bash: line 2: BAR: command not found
bash: line 3: BAZ: command not found
...

其中 FOO、BAR、BAZ 等是每行的第一個單字本機檔案.txt:

FOO     FOO_PARAM1
BAR     BAR_PARAM1
BAZ     BAZ_PARAM2
...

所以,看起來"bash -s"遠端伺服器正在解釋本機檔案.txt作為腳本文件,而不是輸入文件本地腳本.sh。有什麼方法可以解決這個問題(除了創建包裝腳本之外)?

答案1

雖然ssh提供了兩個獨立的輸出流(用於 stdout 和 stderr),但它只提供一個輸入流(stdin)。因此,您需要透過不同的機制傳遞腳本內容和輸入檔。

例如,一個透過變量,一個透過 stdin:

LC_CODE=$(cat local_script.sh) ssh host 'eval "$LC_CODE"' < input

(假設您的ssh客戶端傳遞LC_*變數(SendEnvin ssh_config)並且sshd伺服器接受它們(AcceptEnvin sshd_config))

或簡單地將 的內容local_script.sh作為遠端 shell 程式碼傳遞,假設遠端使用者的登入 shell 是該腳本語法的正確選擇:

ssh host "$(cat local_script.sh)" < input

或將代碼和輸入連接到ssh的 stdin,如下所示:

{
  echo '{'; cat local_script.sh; echo '}; exit'
  cat input
} | ssh host 'bash -s some arguments'

這裡使用bashbecausebash將負責一次一個位元組地讀取輸入,以免讀取超過該}; exit行,而並非所有其他shell都這樣做。

或如果sed遠端主機上是 GNU sed

echo '#END-OF-SCRIPT' | cat local_script.sh - input |
  ssh host 'set some arguments; eval "$(sed -u "/^#END-OF-SCRIPT/q")"'

(此處由遠端使用者的登入 shell 評估程式碼並假設它類​​似於 Bourne)

答案2

這是使用 BASH 'here-strings' 運算子 ('<<<') 的更優雅的解決方案

ssh -t host "/bin/bash <(base64 --decode <<<'$(base64 < script)' )"

IT 取得腳本,將其轉換為 Base64 字串,在 SSH 命令中將其轉換回來並將其作為管道檔案名稱提供給 bash。

對於建立互動式 shell 的腳本,請在“管道檔案名稱”前面加上“--rcfile”

ssh -t host "/bin/bash --rcfile <(base64 --decode <<<'$(base64 < script)' )"

更多關於... https://antofthy.gitlab.io/info/apps/ssh_remote_commands.txt

答案3

這很有效,甚至可以讓您將多個文件的內容傳遞給腳本:

ssh host "bash -s -- '$(cat local_file_1.txt)'  '$(cat local_file_2.txt)'" < local_script.sh

解釋是它將在登入時ssh執行bash -s,腳本參數是 後的所有內容--$1的內容也將如此,local_file_1.txt$2內容也將如此local_file_2.txtbash -s從來自 的 stdin 讀取命令< local_script.sh

相關內容