上一篇文章寫到的權限檢查腳本,后來我又加入了 apk size 對比的功能,分享給組內同事使用后,暴露出一個問題:腳本輸出的 apk size 和 Jenkins 出包信息以及電腦上顯示的存儲大小都有差異。那么,以何為准呢?
以下是同事的提問及我的回復(已過濾敏感信息):
使用腳本發現 APK SIZE 的檢測結果,與在 Jenkins 出包信息有差異,且差異不小。
電腦上顯示的存儲大小也有差異,具體截圖如下:
1、使用腳本檢查兩個版本結果為:
腳本中計算 apk size 的命令是:ls -s -k
ls -- list directory contents
-s Display the number of file system blocks actually used by each
file, in units of 512 bytes, where partial units are rounded up
to the next integer value. If the output is to a terminal, a
total sum for all the file sizes is output on a line before the
listing. The environment variable BLOCKSIZE overrides the unit
size of 512 bytes.
-k If the -s option is specified, print the file size allocation in
kilobytes, not blocks. This option overrides the environment
variable BLOCKSIZE.
如上所示,這個命令的作用是顯示每個文件實際占有的文件系統中塊(Block)的數量,每個塊的大小是 512 字節。
確實,這個命令輸出的信息有問題,在新腳本中已更正。具體的解釋見第2&3條回復。
2、查看 Jenkins 出包信息,大小差異為 0.25M:
Jenkins 計算 apk size 的命令是:du -k
du -- display disk usage statistics
-k Display block counts in 1024-byte (1-Kbyte) blocks.
du 是 Linux 系統中查看磁盤使用空間的命令,輸出的是文件占有系統磁盤空間的塊的數量(和上面提到的 ls -s 功能一樣),加上參數 -k 可將塊的數量轉換成 1024 字節(1KB)的形式輸出。
本來我最早寫 apk size 對比的腳本時也打算用 du -k 的命令,結果發現這個命令在不同系統中會因為塊的大小和文件占有磁盤空間大小的不同導致顯示的 apk size 大小有差異。
后來轉用了 ls -s -k 命令,結果發現,ls -s -k 踏入的是同樣的坑(在不同系統中會因為塊的大小和文件占有磁盤空間大小的不同導致顯示的 apk size 大小有差異)。
說到這里,不得不提一下文件大小的兩個概念:
(1)文件占用磁盤空間的大小
(2)文件實際的大小
du -k 和 ls -s -k 屬於第一種,計算的都是文件占用磁盤空間的大小。在電腦的文件系統中,存儲是以塊(Block)為單位的,不同的系統塊的大小不一樣,比如說 macOS 一個塊的大小是 4096 字節。假設一個文件有 4097 字節,4097-4096=1,這個文件在占用了一個塊之后,還有一個字節會占用到一個塊,而塊與塊之間是不共享空間的,也就是說,剩下的 1 字節占用了一個塊,這個塊還空出 4095 字節,但是無法用於存儲其他文件。所以,這個大小為 4097 字節的文件占用了 2 個塊。而 du -k 和 ls -s -k 計算的正是每個文件占用塊的多少。同理可得,其中必定有部分塊是沒有占滿的,所以和實際的文件大小有差異。
那么,如何獲得文件實際的大小呢?請看第三條回復
3、查看電腦中存儲信息,V122 出現了兩個大小的值:
截圖中,“通用”條目下的“大小”一行,15538958 字節表示的正是文件實際的大小。而括號中的“磁盤上的 16.4MB”,網上查到有人說是“壓縮數據真正需要多少存儲空間”(http://www.kbase101.com/question/47039.html),無法判斷真假。
文件名右邊的“15.5MB”,其實是 15538958bytes/1000/1000=15.538958MB,約等於 15.5MB。
文件的實際大小,可通過 ls -l 獲得:
新的腳本已更新為獲取文件的實際大小。
腳本如下:
#!/usr/bin/env bash
#清空上次運行后產生的文件
if [[ -f permission_old.txt ]]; then
rm permission_old.txt permission_new.txt
fi
#讀取apk文件地址
read -p "請輸入上個版本apk文件存放地址:" apk_old
read -p "請輸入最新版本apk文件存放地址:" apk_new
#檢查apk size
b_size_old=`ls -l ${apk_old} | awk '{print $5}'`
k_size_old=`awk 'BEGIN{printf "%.2f\n", "'${b_size_old}'"/'1024'}'`
m_size_old=`awk 'BEGIN{printf "%.2f\n", "'${k_size_old}'"/'1024'}'`
b_size_new=`ls -l ${apk_new} | awk '{print $5}'`
k_size_new=`awk 'BEGIN{printf "%.2f\n", "'${b_size_new}'"/'1024'}'`
m_size_new=`awk 'BEGIN{printf "%.2f\n", "'${k_size_new}'"/'1024'}'`
#aapt命令解析apk,輸出權限到文件
aapt d badging ${apk_old} | grep "uses-permission:" | awk -F "'" '{print $2}' > permission_old.txt
aapt d badging ${apk_new} | grep "uses-permission:" | awk -F "'" '{print $2}' > permission_new.txt
#遍歷新版本權限列表,對比舊版本權限列表是否相同,不同則為新增
for x in $(cat permission_new.txt); do
if cat permission_old.txt | grep ${x} > /dev/null; then
echo "hello, world" > /dev/null
else
echo ${x} >> permission_increase.txt
fi
done
#遍歷舊版本權限列表,對比新版本權限列表是否相同,不同則為新減少
for y in $(cat permission_old.txt); do
if cat permission_new.txt | grep ${y} > /dev/null; then
echo "hello, world" > /dev/null
else
echo ${y} >> permission_decrease.txt
fi
done
#判斷permission_increase.txt是否存在:存在,輸出新增權限提醒;不存在,輸出無新增權限
if [[ ! -f permission_increase.txt ]]; then
echo "無新增權限"
else
echo "新增權限:"
cat permission_increase.txt
#刪除新增權限文件
rm permission_increase.txt
fi
#判斷permission_decrease.txt是否存在:存在,輸出新減少權限提醒;不存在,輸出無新減少權限
if [[ ! -f permission_decrease.txt ]]; then
echo "無新減少權限"
else
echo "新減少權限:"
cat permission_decrease.txt
#刪除新減少權限文件
rm permission_decrease.txt
fi
#輸出apk size
echo "------"
echo "上個版本apk size: ${m_size_old}MB(${k_size_old}KB)"
echo "最新版本apk size: ${m_size_new}MB(${k_size_new}KB)"
#對比兩個版本的apk size大小變化
if [[ `echo "${m_size_new} > ${m_size_old}" | bc` -eq 1 ]]
then
exceeded_size=$(printf "%.2f" `echo "scale=2;${m_size_new}-${m_size_old}"|bc`)
echo "最新版本比上個版本增加${exceeded_size}MB"
else
echo "apk size未增加"
fi
歡迎關注微信公眾號"測試開發Stack"