Watch at Ease看見世界,讀懂生活。

科技 · 實用指南

find 顯示「paths must precede expression」?先證明 shell 展開,再改指令

這個錯誤通常表示 shell 或包裝器在 find 解析前改變了參數清單,並不證明起始路徑寫錯。先擷取真實 argv,區分起始路徑與運算式,替交給 find 的模式加上引號,再以零個、一個及多個符合項測試後才恢復破壞性操作。

未引用萬用字元在 find 解析前展開為多個參數的示意圖
示意:檢查 find 真正收到的參數向量,不要只相信輸入時的指令文字。 Watch at Ease

這則訊息表示 find 無法在收到的起始點與運算式之間維持清楚邊界;它本身不能證明 -name 前的目錄錯誤。

最有價值的證據是真實參數向量。先證明 shell 或包裝器交給 find 的內容,替每個參數分類,再以零個、一個和多個符合項驗證修正,最後才恢復會修改檔案的動作。

1. 保存原始指令與真實 argv 邊界

記錄 shell、工作目錄、find 版本、完整指令、結束碼與 stderr。安全重現時逐一列印已引用的參數;不要把機密寫入記錄,也不要用 eval 重建指令。

相同的可見指令經互動式 shell、腳本、別名、變數或建置工具後,可能產生不同 argv,因此只看顯示文字不夠。

2. 重現零個、一個與多個符合項

在無害目錄測試相同模式。未引用的 *.txt 可能保持一個詞、展開成一個路徑而看似正常,或展開成多個路徑並被 find 當成額外起始點。

要由 find 比對的模式應加引號或跳脫。Bash、zsh 對無符合模式的差異應記錄為證據,不要靠猜測修正。

3. 替每個參數標註角色

逐列寫下收到的參數:先是真正起始路徑,再是 -name 等測試與 -print 等動作。核對每個 primary 需要的參數數量。

不要把所有陌生參數都移到前面;確認它是路徑、選項、測試運算元、群組符號或動作,並以目前 find 實作文件為準。

4. 在變數與包裝器中保留邊界

Bash 中未引用的參數展開還會經過分詞與路徑名稱展開。多參數指令優先使用陣列,必須維持單一參數的純量要加引號,並分別檢查別名、函式、服務包裝器與建置工具替換。

不要用 eval 或單一拼接字串修正;再次解析會改變空白與萬用字元意義,也可能造成注入風險。

5. 在破壞性操作前證明修正

先以 -print 取代修改操作,驗證零、單、多符合項,以及含空白與前導連字號的名稱,並確認正式包裝器傳入相同 argv。

確認選取集合正確後,才在小範圍及可回復條件下恢復 -delete、-exec。錯誤消失、輸出正確且參數角色不再改變才算驗收通過。

區分 shell 展開、起始路徑、find 運算式與包裝器邊界的決策圖
示意:依角色處理每個參數,再以只列印樣例驗收修正。 Watch at Ease