如何 ssh 並執行包含在 if else 中的多個命令?
我想使用 ssh 從各種伺服器擷取一些數據並在某些條件下執行一些命令。
我不想這樣做:
if ssh $host test -f /file; then # If file exists var=$(ssh $host long pipeline) else # if it doesn't var=$(ssh $host another long pipeline) fi
因為它會使過程更長。我想在遠端機器上執行 if else 。
我嘗試了幾種方法,但我沒有運氣。
var=$(ssh $host if [ -f /file ]\; then long pipeline1 \; else long pipeline2 \; fi)
基於這個答案,它可以工作,但 pipeline1 的最後一個命令假定它
else
和 pipeline2 的其餘部分作為它的參數。command: can't read else: No such file or directory ... command: can't read fi: No such file or directory
然後我嘗試了這個
var=$(ssh $host test -f /file \&\& pipeline1 \|\| pipeline2)
同樣, pipeline1 的最後一個命令被
||
視為其參數。我也在下面嘗試過(基於this),它正在工作:
do_this () { if [ -f /file ]; then pipeline1 else pipeline2 fi } var=$(ssh $host "$(set); do_this")
然而,它會列印不影響我的變數的不需要的錯誤消息,但它對我的腳本來說很難看。
bash: line 1: BASHOPTS: readonly variable bash: line 8: BASH_VERSINFO: readonly variable bash: line 24: EUID: readonly variable bash: line 71: PPID: readonly variable bash: line 82: SHELLOPTS: readonly variable bash: line 92: UID: readonly variable
有什麼建議麼?
更新
我想我必須包括我的管道是什麼,基本上它只是一堆文本處理:
cat file | grep "something" | sed 's/.*="\(.*\)"/\1/' | tr ' ' '-'
根據Jetchisel的回答,簡而言之,我必須用單引號括起我的命令。
var=$(ssh $host 'if [ -f /file ]; then cat file | grep "something" | sed 's/.*="\(.*\)"/\1/' | tr ' ' '-' ; else cat otherfile | ... ; fi'
我得到了
tr: invalid option -- ';'
。tr
當作;
它的論據。它使用
heredoc
:var=$(ssh $host <<-EOF if [ -f file ]; then pipeline1 else pipeline2 fi EOF )
然而,由於我在 sed 中使用的正則表達式,它破壞了 vim 的著色。我現在會接受
heredoc
作為答案。更新 2:我相信我的問題不是sshpass 中的多個命令的重複,我的情況更具體,而另一個執行緒一般會問它。
在:
ssh host code
ssh
實際上執行一個 shell(目標使用者的登錄 shell)來解釋您作為參數傳遞的程式碼。如果給出了多個參數,ssh 將它們與空格連接起來,並再次讓使用者的登錄 shellhost
解釋它。通常,您希望將單個程式碼參數傳遞給並確保它用單
ssh
引號引起來,以確保本地 shell 不會進行擴展。如果您知道遠端使用者的登錄 shell 類似於 Bourne/POSIX,那麼您所要做的就是:
var=$(ssh "$host" ' if [ -f /file ]; then pipeline1 else pipeline2 fi' )
如果要遠端解釋的程式碼必須在其中包含單引號,則需要將它們插入為
'\''
(保留單引號,插入帶引號的(帶反斜杠)單引號,重新輸入單引號)。如果您不能保證遠端使用者的外殼,並且您不需要通過其標準輸入將數據傳遞給遠端命令(並且任何遠端命令都不會從其標準輸入讀取,除非它重定向到其他東西而不是 ssh 連接),您可以這樣做:
ssh "$host" sh << 'EOF' if [ -f /file ]; then pipeline1 else pipeline2 fi EOF
通過引用第一個
EOF
,我們確保本地 shell 沒有在 here 文件中進行擴展。我們顯式呼叫sh
以解釋其標準輸入上的程式碼,因此我們知道編寫腳本的語法。這種方法還避免了必須轉義單引號。
您的
cat file | grep "something" | sed 's/.*="\(.*\)"/\1/' | tr ' ' '-'
可以寫成:
<file sed '/something/!d; s/.*="\(.*\)"/\1/; y/ /-/'
所以這給了我們:
ssh "$host" ' file=/path/to/some/file otherfile=/path/to/some/other/file if [ -f "$file" ]; then <"$file" sed '\''/something/!d; s/.*="\(.*\)"/\1/; y/ /-/'\'' else <"$otherfile" ... fi'
(如果遠端使用者的登錄 shell 是例如 csh、tcsh、fish、rc、es、akanga,其語法與 Bourne/POSIX-like 語法不同,這將不起作用)
或者:
ssh "$host" sh << 'EOF' file=/path/to/some/file otherfile=/path/to/some/other/file if [ -f "$file" ]; then <"$file" sed '/something/!d; s/.*="\(.*\)"/\1/; y/ /-/' else <"$otherfile" ... fi EOF