需求場景
我選中一個目錄下的多個檔案,然後對這一批檔案進行相同或類似的操作。比如我選中幾個md檔案,然後對所有檔案中的圖片地址進行更新,這樣就可以把本地儲存的圖片檔案轉移到其他目錄,甚至換成圖床的地址。
思路描述
- 在Path Finder中選擇一個或多個檔案;
- 呼叫KM(Keyboard Maestro)巨集,取出所選檔案的全路徑列表;
- 遍歷上一步得到的列表,呼叫shell依次處理每一個檔案;
獲取選中檔案的路徑
原生KM提供了一個For Each Path in Finder Selection的Action,只支援對Finder中選中的檔案進行操作。因為我基本使用Path Finder進行日常操作,所以我需要實現一個PF版本的類似操作。考慮到實現一個Action的門檻較高,所以暫時選擇使用Macro來實現。原來是打算使用AppleScript來實現,不過最近看到MacOS提供了JXA模式,用JavaScript來操作OS級別的任務。所以儘量使用JXA來實現我的需求。
基礎版
僅支援單一目錄下的檔案
KM提供了Execute JavaScript for Automation的Action,在程式碼框中輸入下面的程式碼。或者把程式碼儲存為.js檔案,在Action中直接呼叫檔案。
// 獲取每個檔案的地址
function pathFolderFile(x) {
var strPath = x.posixPath();
return strPath;
}
// 獲取Path Finder中選中的檔案地址,如果是多個檔案,就用\n符號進行分割
function run() {
var pfSeln = Application("Path Finder").selection();
var selectionList = pfSeln ? pfSeln.map(pathFolderFile) : [];
return selectionList.join("\n");
}
複製程式碼
上面的程式碼整體上很簡單,幾個重點如下:
- 如果沒有選中任何檔案,就返回空列表,避免後續操作出錯。
- 最終需要把多個path結果返回到一個變數中供下一步操作,但是我目前使用的KM7沒有提供List型別的變數,所以我把List的結果轉換為一個用換行符分隔的字串。
- Action中一定要設定 save variable to ,把JXA返回的結果存在變數中。
高階版
增加對資料夾的遞迴操作。
暫時沒有找到JXA的處理方式,待續。。。
依次處理返回的檔案列表
KM提供了For Each這個Action,對剛才返回的字串可以根據換行符進行逐行操作。這個和python等語言裡面的 for X in Y 結構是一樣的,很容易理解。如下圖
呼叫Shell指令碼的坑
KM中的Execute a Shell Script操作,使用的是非互動式模式。即,當在KM中呼叫shell的時候,不會使用當前使用者的環境變數。這和通過crontab呼叫shell的場景是一模一樣的。因為最開始忽略這個細節,所以出現兩個問題
- 呼叫python的時候,用了系統預設的2.7版,而不是3.5版。
- 在處理UTF-8字符集的時候報錯,因為沒有設定 export LANG=zh_CN.UTF-8。
解決這個問題的辦法也很簡單,和crontab執行程式碼一個套路,只需要在執行shell之前先執行當前使用者的環境配置檔案。如下
# 設定環境變數
source ${HOME}/.bash_profile
複製程式碼
完整的KM Macro
這裡把JXA儲存為.js檔案進行呼叫