Bash

在 shell 腳本中通過 ssh 查找使用 exec

  • June 29, 2014

因此,我試圖從 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"

引用自:https://unix.stackexchange.com/questions/139766