在 shell 腳本中通過 ssh 查找使用 exec
因此,我試圖從 shell 腳本中執行以下操作;
ssh -q $CUR_HOST "cd $LOGS_DIR; echo cd $LOGS_DIR; find . -name *.log -mmin +1440 -exec gzip {} \; exit"
當它執行時,它會產生以下錯誤;
find: paths must precede expression Usage: find [-H] [-L] [-P] [path...] [expression]
我根據在 Google 上找到的東西嘗試了許多變體,但似乎沒有一個可以解決這個問題。誰能告訴我這有什麼問題?
作為旁注,當我手動登錄到目標主機並在那裡執行相同的 find 命令時,它工作得很好。所以,我被引導認為這與嵌入在 ssh 命令的雙引號中的命令有關。
您忘記添加“;”:
ssh -q $CUR_HOST "cd $LOGS_DIR; echo cd $LOGS_DIR; find . -name *.log -mmin +1440 -exec gzip {} \;; exit"
由於缺少
;
, find 解釋exit
為路徑。
有幾個語法問題,其中一個是致命的,另一個可能會在某個時候咬你。
順便說一句,您可以使用
+
而不是;
結束-exec
指令;這種方式gzip
會分批執行,速度稍微快一些。如果值為,
LOGS_DIR
則/somewhere/with/logs
在遠端主機上執行以下命令:cd /somewhere/with/logs; echo cd /somewhere/with/logs; find . -name *.log -mmin +1440 -exec gzip {} \; exit
或者,用換行符代替等效的分號運算符:
cd /somewhere/with/logs echo cd /somewhere/with/logs find . -name *.log -mmin +1440 -exec gzip {} \; exit
當
find
看到指令exit
後的那個虛假時-exec … ;
,它不知道如何處理它;它冒著一個(錯誤的)猜測,你的意思是它是一條穿越的路徑。您需要一個命令分隔符:;
在之後放置另一個\;
(之前有或沒有空格)。第二個問題是萬用字元模式
*.log
將在目錄中展開/somewhere/with/logs
。如果存在匹配文件(即,如果存在格式為 的文件/somewhere/with/logs/something.log
),則該模式將被該匹配文件替換。僅當遠端 shell 沒有匹配項*.log
保持不變並且 find 可以看到時。在模式周圍添加引號以防止這種情況。第三個問題是 的值
LOGS_DIR
。它在本地擴展為一個字元串,該字元串在遠端端作為 shell 腳本執行。因此,如果其中有任何 shell 特殊字元(空格、$
等),則可以執行任意遠端命令。引用大多數字元的一種快速而簡單的方法是在變數擴展周圍加上單引號;僅當值包含單引號時才會中斷。如果您的本地腳本正在執行 bash,您可以將單引號替換為 4 字元序列'\''
以保護 的值LOGS_DIR
:ssh -q "$CUR_HOST" "cd '${LOGS_DIR//\'/\'\\\'\'}'; find . -name '*.log' -mmin +1440 -exec gzip {} +; exit"