天天看點

避免使用裸的 mkdir -p

首先說明一下,這裡的裸是指不事先判斷目錄是否存在,直接使用 mkdir -p 建立。

如果經常與檔案系統打交道,少不了會有建立目錄的操作。

比如,我們想在某台機器上同步某個檔案目錄,就需要確定它的父目錄存在。如果不存在,可能還需要根據需要動态建立。

系統提供了很多可以直接使用的指令,它的好處是顯而易見的,當你不想在遠端裝 agent 來操作,而選擇使用 ssh 連接配接,直接使用這些現成指令是一個簡單有效的選擇。

如果建立目錄,可以選擇使用 mkdir 指令。如果系統可能有多級目錄不存在,我們可能會考慮 -p 選項。

-p 類似于程式設計裡面的遞歸思想,但是有一點要注意注意注意,它是從檔案系統的根開始判斷的,而不是從最完整的目錄。

strace mkdir -p /tmp/foo/bar/bazz/baxx/apple/boy/cat/dog

# ...
mkdir("/tmp", )                     = - EEXIST (File exists)
chdir("/tmp")                           = 
mkdir("foo", )                      = 
open("foo", O_RDONLY|O_NOCTTY|O_NONBLOCK|O_DIRECTORY|O_NOFOLLOW) = 
fchdir()                               = 
close()                                = 
mkdir("bar", )                      = 
open("bar", O_RDONLY|O_NOCTTY|O_NONBLOCK|O_DIRECTORY|O_NOFOLLOW) = 
fchdir()                               = 
close()                                = 
mkdir("bazz", )                     = 
open("bazz", O_RDONLY|O_NOCTTY|O_NONBLOCK|O_DIRECTORY|O_NOFOLLOW) = 
fchdir()                               = 
close()                                = 
mkdir("baxx", )                     = 
open("baxx", O_RDONLY|O_NOCTTY|O_NONBLOCK|O_DIRECTORY|O_NOFOLLOW) = 
fchdir()                               = 
close()                                = 
mkdir("apple", )                    = 
open("apple", O_RDONLY|O_NOCTTY|O_NONBLOCK|O_DIRECTORY|O_NOFOLLOW) = 
fchdir()                               = 
close()                                = 
mkdir("boy", )                      = 
open("boy", O_RDONLY|O_NOCTTY|O_NONBLOCK|O_DIRECTORY|O_NOFOLLOW) = 
fchdir()                               = 
close()                                = 
mkdir("cat", )                      = 
open("cat", O_RDONLY|O_NOCTTY|O_NONBLOCK|O_DIRECTORY|O_NOFOLLOW) = 
fchdir()                               = 
close()                                = 
mkdir("dog", )                      = 
# ...
           

天哪,每一級目錄,如果存在,會對應兩個系統調用(mkdir、chdir);如果不存在,會對應四個系統調用(mkdir、open、fchdir、close)。

當偶而執行一次這類操作,問題倒還不是特别明顯。但是當我們頻繁執行大量與此類似的深層目錄建立的操作時,系統的性能很快就會有所反應。

好的實踐是怎樣的呢?

首先,我們要建立的目錄很有可能已經存在。這一步判斷可以避免 mkdir -p 無條件地執行。test 可以判斷目錄或檔案是否存在,它隻是一個簡單的 stat 系統調用,very cheap。

其次,避免使用絕對路徑。如果我們确定 /tmp/foo/bar/bazz/baxx/apple 已經存在,隻需要從 apple 建立 boy/cat/dog 這三個目錄就可以了,可以節省 1 * 2 + 5 * 4 = 22 次系統調用,這次真是賺到了。

當然,如果隻是手動建立目錄,-p 并沒有太大的副作用。視情況而定。