本文微信公眾號「AndroidTraveler」首發。
背景
最近,要重裝 macOS,所以需要拷貝數據進行備份。
而這個備份過程差點讓我抓狂,速度超級慢,等待時間很是煎熬。
分析
這邊看了一下,主要是因為文件過多對數據遷移速度造成了較大的影響。
大家知道,我們用 AndroidStudio 新建一個 HelloWorld 項目,系統會自動幫我們生成很多文件。
這邊建了一個,並查看了文件(包括目錄)數目,有 85 個文件,這還是最簡單的項目。
假設一般的項目平均 1000 個文件,有 100 個項目則文件數目達到 10 萬級別。(PS:我遇到過一個項目就高達 5 萬多個文件數目的)
如果你直接拷貝的話,那么耗時是非常長的,尤其是對於機械硬盤而言。
那么我們能否壓縮一下呢?
這么大量的文件,如果你一次性全部壓縮成一個文件,那么耗時也是比較大的。
因此這邊就想可否每個項目單獨壓縮,這樣耗時是不是就相對要少一些呢?
但是直接在 mac 上面右鍵並沒有批量壓縮選項。
選擇多個系統會以為你要把多個目錄壓縮成一個文件。
我們知道,壓縮文件可以使用命令行。
所以我們可以通過腳本來實現批處理壓縮文件。
實戰
那下面我們就一步一步來完成批處理壓縮腳本的編寫。
Step 1: 創建並運行腳本
我們假設創建的腳本名字為 batch_zip.sh。
在終端上執行下面命令:
touch batch_zip.sh;chmod u+x batch_zip.sh
第一條命令是創建 batch_zip.sh 文件,第二個命令是為該文件增加可執行權限,因為我們的腳本最后是需要運行的。
如果你是直接拷貝我文末鏈接上的腳本文件,你下載到本地只需要執行第二條命令即可。
Step 2: 熟悉壓縮命令
首先我們需要了解壓縮命令。最基本的壓縮命令如下:
zip 壓縮后文件.zip 壓縮前文件
由於我們有遞歸壓縮需求,因此需要添加 -r 選項。
另外壓縮過程默認會顯示壓縮詳情,比如具體壓縮了哪些文件。
如果你不想知道具體壓縮過程,可以添加 -q 選項。
我們將這兩個選項組合起來,最終壓縮命令就是:
zip -rq 壓縮后文件.zip 壓縮前文件
你以為這就結束了?
假設壓縮前的文件命名帶有空格,你直接用上面的命令,那么會出現意想不到的結果,所以為了應對這種情況,我們需要稍作修改,給文件名加個引號(單引號雙引號都可以)括起來。
zip -rq '壓縮后文件.zip' '壓縮前文件'
Step 3: 羅列當前目錄的所有文件
我們知道,羅列當前目錄所有文件只需要使用 ls 命令即可。
所以我們將這個命令返回的結果集用一個變量保存起來,然后我們打印看下效果。
我們修改我們的腳本文件,修改后如下:
FILES=`ls`
echo $FILES
注意這里不是單引號,這里的符號位置在鍵盤左上角處。
然后我們運行腳本:
./batch_zip.sh
就可以看到羅列出的文件了。
Step 4: 循環遍歷所有文件
因為我們的文件都放在集合里面,因此我們需要逐個遍歷獲取,然后逐個進行壓縮操作。
這里用到了循環語句,基本結構如下:
for element in array
do
// TODO
done
// TODO 里面就是你具體要處理的事情。
所以我們可以修改腳本文件如下:
FILES=`ls`
for file in $FILES
do
echo $file
done
這樣運行之后就會逐個打印羅列后的文件名。
如果你當前目錄有文件的名字是包含空格的話,你會發現打印出來的有空格文件名被隔開了。
比如你的文件名是 test 2.txt,則打印會打印出兩行,分別是 test 和 2.txt。
因為 ls 命令列出的不同文件就是用空格隔開的。
所以一般情況下推薦命名不要有空格,如果需要分隔,可以用下划線 _。
但是假設真的有怎么辦?
別慌,問題不大。
直接 show 代碼如下:
#!/bin/bash
SAVEIFS=$IFS
IFS=$(echo -en "\n\b")
for file in *
do
echo $file
done
IFS=$SAVEIFS
具體腳本分析我們就不展開了。大家感興趣可以看文末參考鏈接。
Step 5: 只壓縮目錄
其實我們壓縮的是對於包含大量瑣碎文件的目錄,因此只需要壓縮目錄就可以了。
另外我們的腳本文件因為是文件,包括壓縮文件也是普通文件,因此不需要額外進行排除。
改造后代碼如下:
#!/bin/bash
SAVEIFS=$IFS
IFS=$(echo -en "\n\b")
for file in *
do
if [ -d $file ]
then
echo $file
fi
done
IFS=$SAVEIFS
修改點在 do-done 塊里面。
主要是增加了一個判斷,當文件是目錄時,才執行打印操作。
Step 6: 替換打印為壓縮命令
結合 Step2 我們最終的腳本命令為:
#!/bin/bash
SAVEIFS=$IFS
IFS=$(echo -en "\n\b")
for file in *
do
if [ -d $file ]
then
zip -rq $file.zip $file
echo $file was successfully compressed.
fi
done
IFS=$SAVEIFS
壓縮成功每個文件都會打印一句壓縮成功。
使用
只需要將腳本命令拷貝到你需要壓縮的目錄下面,就可以對跟腳本文件同級的所有目錄進行壓縮。
記得腳本文件需要有可執行權限才能運行。
如果提示沒有權限,可以先運行如下命令添加權限。
chmod u+x batch_zip.sh
下載
大家可以到 GitHub 倉庫上面去直接下載本文最終生成的腳本文件。
https://github.com/nesger/EffectiveTools/blob/master/shell/batch_zip.sh
里面的 README.md 也有具體的用法說明。
優化點
這個腳本命令還有很多地方可以優化,有待大家去完善。
這里列舉如下;
- 支持壓縮指定目錄而不是固定為當前目錄,指定目錄通過執行腳本時參數帶入
- 壓縮結束后告知本次成功壓縮的總數目
- 增加一個邏輯判斷,壓縮成功后是否刪除原文件?可以通過執行腳本時參數帶入
這里就不再描述了,相信對於讀者來說,要實現這些優化也是很簡單的事情。
溫馨提示
其實如果你是要換機器,而且當前系統沒有 bug 的話。
推薦使用時間機器(Time Machine)進行系統遷移。
它相當於把你一台機器上的整個系統(包括文件)進行一個遷移,省去了你重新安裝應用程序和搭建環境的時間。
參考鏈接:
https://www.cyberciti.biz/tips/handling-filenames-with-spaces-in-bash.html
https://www.cnblogs.com/cocowool/archive/2013/01/15/2861904.html