hi~你不知道的vim小祕密
你不知道的vim小祕密
大家先了解一些背景知識:
1) 給檔案增加了i許可權,那檔案不能被更改,不能刪除,也不能修改名字以及許可權。
2) 給檔案增加a許可權,檔案可以追加內容,不能刪除,不能修改內容,不能修改名字以及許可權。
3) vim一個檔案,如果不正常退出,再次編輯時是會提示一些資訊的,並且有一個隱藏的檔案.xxx.swp
瞭解以上知識後,再來看下面的現象:
1) 如果給一個檔案增加a許可權,用vim編輯檔案,增加內容(注意是在檔案末尾增加內容,不要修改其他內容),並不會成功。
2) 如果給一個目錄增加i許可權或者a許可權,在該目錄下面vim一個檔案,更改檔案內容可以正常儲存。
既然a許可權可以追加內容,那為何vim一個檔案在末尾增加內容不能成功?
既然i許可權不能修改,那為何在目錄裡面變更檔案內容卻可以成功?
關於這兩點,你有沒有疑惑?下面我們來分析原因。
先不管i或者a許可權,在一個沒有i或者a許可權的目錄下,編輯一個沒有i或者a許可權的檔案,用strace來檢視其執行過程。
mkdir /tmp/test
strace vim /tmp/test/aminglinux.txt 2>/tmp/vim.log
寫入一個數字1,然後儲存退出。再來檢視vim.log的內容。
less /tmp/vim.log
大部分內容你不用關心,只需要看這幾行:
stat("/tmp/test/aminglinux.txt", 0x7fff072ecb10) = -1 ENOENT (No such file or directory)
access("/tmp/test/aminglinux.txt", W_OK) = -1 ENOENT (No such file or directory)
open("/tmp/test/aminglinux.txt", O_RDONLY) = -1 ENOENT (No such file or directory)
readlink("/tmp/test/aminglinux.txt", 0x7fff072eb360, 4095) = -1 ENOENT (No such file or directory)
open("/tmp/test/.aminglinux.txt.swp", O_RDONLY) = -1 ENOENT (No such file or directory)
open("/tmp/test/.aminglinux.txt.swp", O_RDWR|O_CREAT|O_EXCL, 0600) = 3
open("/tmp/test/.aminglinux.txt.swx", O_RDONLY) = -1 ENOENT (No such file or directory)
open("/tmp/test/.aminglinux.txt.swx", O_RDWR|O_CREAT|O_EXCL, 0600) = 4
unlink("/tmp/test/.aminglinux.txt.swx") = 0
unlink("/tmp/test/.aminglinux.txt.swp") = 0
stat("/tmp/test/.aminglinux.txt.swp", 0x7fff072ec310) = -1 ENOENT (No such file or directory)
lstat("/tmp/test/.aminglinux.txt.swp", 0x7fff072ec3e0) = -1 ENOENT (No such file or directory)
lstat("/tmp/test/.aminglinux.txt.swp", 0x7fff072ec8a0) = -1 ENOENT (No such file or directory)
open("/tmp/test/.aminglinux.txt.swp", O_RDWR|O_CREAT|O_EXCL|O_NOFOLLOW, 0600) = 3
stat("/tmp/test/aminglinux.txt", 0x7fff072eac40) = -1 ENOENT (No such file or directory)
stat("/tmp/test/aminglinux.txt", 0x7fff072ebe20) = -1 ENOENT (No such file or directory)
stat("/tmp/test/aminglinux.txt", 0x7fff072eadf0) = -1 ENOENT (No such file or directory)
write(1, ""/tmp/test/aminglinux.txt"", 26) = 26
stat("/tmp/test/aminglinux.txt", 0x7fff072ec050) = -1 ENOENT (No such file or directory)
open("/tmp/test/aminglinux.txt", O_WRONLY|O_CREAT|O_TRUNC, 0666) = 4
stat("/tmp/test/aminglinux.txt", {st_mode=S_IFREG|0644, st_size=2, ...}) = 0
stat("/tmp/test/aminglinux.txt", {st_mode=S_IFREG|0644, st_size=2, ...}) = 0
unlink("/tmp/test/.aminglinux.txt.swp") = 0
看起來亂亂的,其實大概的過程就是vim /tmp/test/aminglinux.txt時,先看有沒有.aminglinux.txt.swp以及.aminglinux.txt.swx,因為這兩個檔案就是vim產生的臨時檔案,swp先產生,如果swp存在就產生第二個swx。寫入的內容先存到swp裡,當儲存退出vim時,再把swp的內容存到aminglinux.txt裡,最後刪除掉swp檔案。
有了這個認識之後,我們再來分析上面提到的現象1。如果檔案給了a許可權,那麼在編輯該檔案時,會產生swp檔案,當儲存退出時,swp檔案內容會寫入該檔案,這相當於更改該檔案,很線上a許可權是不允許的。
再來分析現象2,按照我們的推測,如果目錄給了a許可權,增加檔案沒問題,也就是說產生swp或者swx檔案沒有問題,當然把swp或者swx內容寫入到檔案裡時也不會有問題,但swp或者swx檔案卻不會被刪除了,所以再次編輯檔案時就會提示臨時檔案已經存在了。但這並不會影響修改檔案內容。
如果給目錄設定了i許可權的話,vim編輯檔案,要產生swp或swx肯定會出錯啊,但為何依然能正常編輯檔案? 下面繼續用strace來分析一下。
chattr +i /tmp/test
strace vim /tmp/test/aminglinux.txt 2> /tmp/vim.log
看vim.log裡面和aminglinux.txt相關的資訊
stat("/tmp/test/aminglinux.txt", {st_mode=S_IFREG|0644, st_size=4, ...}) = 0
stat("/tmp/test/aminglinux.txt", {st_mode=S_IFREG|0644, st_size=4, ...}) = 0
stat("/tmp/test/aminglinux.txt", {st_mode=S_IFREG|0644, st_size=4, ...}) = 0
stat("/tmp/test/aminglinux.txt", {st_mode=S_IFREG|0644, st_size=4, ...}) = 0
access("/tmp/test/aminglinux.txt", W_OK) = 0
open("/tmp/test/aminglinux.txt", O_RDONLY) = 3
readlink("/tmp/test/aminglinux.txt", 0x7fff49efc6f0, 4095) = -1 EINVAL (Invalid argument)
open("/tmp/test/.aminglinux.txt.swp", O_RDONLY) = -1 ENOENT (No such file or directory)
open("/tmp/test/.aminglinux.txt.swp", O_RDWR|O_CREAT|O_EXCL, 0600) = -1 EACCES (Permission denied)
stat("/tmp/test/.aminglinux.txt.swp", 0x7fff49efd6a0) = -1 ENOENT (No such file or directory)
lstat("/tmp/test/.aminglinux.txt.swp", 0x7fff49efd770) = -1 ENOENT (No such file or directory)
lstat("/tmp/test/.aminglinux.txt.swp", 0x7fff49efdc30) = -1 ENOENT (No such file or directory)
open("/tmp/test/.aminglinux.txt.swp", O_RDWR|O_CREAT|O_EXCL|O_NOFOLLOW, 0600) = -1 EACCES (Permission denied)
readlink("/tmp/test/aminglinux.txt", 0x7fff49efc6f0, 4095) = -1 EINVAL (Invalid argument)
open("/root/tmp/aminglinux.txt.swp", O_RDONLY) = -1 ENOTDIR (Not a directory)
open("/root/tmp/aminglinux.txt.swp", O_RDWR|O_CREAT|O_EXCL, 0600) = -1 ENOTDIR (Not a directory)
stat("/root/tmp/aminglinux.txt.swp", 0x7fff49efd6a0) = -1 ENOTDIR (Not a directory)
lstat("/root/tmp/aminglinux.txt.swp", 0x7fff49efd770) = -1 ENOTDIR (Not a directory)
lstat("/root/tmp/aminglinux.txt.swp", 0x7fff49efdc30) = -1 ENOTDIR (Not a directory)
open("/root/tmp/aminglinux.txt.swp", O_RDWR|O_CREAT|O_EXCL|O_NOFOLLOW, 0600) = -1 ENOTDIR (Not a directory)
readlink("/tmp/test/aminglinux.txt", 0x7fff49efc6f0, 4095) = -1 EINVAL (Invalid argument)
open("/var/tmp/aminglinux.txt.swp", O_RDONLY) = -1 ENOENT (No such file or directory)
open("/var/tmp/aminglinux.txt.swp", O_RDWR|O_CREAT|O_EXCL, 0600) = 4
open("/var/tmp/aminglinux.txt.swx", O_RDONLY) = -1 ENOENT (No such file or directory)
open("/var/tmp/aminglinux.txt.swx", O_RDWR|O_CREAT|O_EXCL, 0600) = 5
unlink("/var/tmp/aminglinux.txt.swx") = 0
unlink("/var/tmp/aminglinux.txt.swp") = 0
stat("/var/tmp/aminglinux.txt.swp", 0x7fff49efd6a0) = -1 ENOENT (No such file or directory)
lstat("/var/tmp/aminglinux.txt.swp", 0x7fff49efd770) = -1 ENOENT (No such file or directory)
lstat("/var/tmp/aminglinux.txt.swp", 0x7fff49efdc30) = -1 ENOENT (No such file or directory)
open("/var/tmp/aminglinux.txt.swp", O_RDWR|O_CREAT|O_EXCL|O_NOFOLLOW, 0600) = 4
chmod("/var/tmp/aminglinux.txt.swp", 0644) = 0
open("/tmp/test/aminglinux.txt", O_RDONLY) = 3
stat("/tmp/test/aminglinux.txt", {st_mode=S_IFREG|0644, st_size=4, ...}) = 0
stat("/tmp/test/aminglinux.txt", {st_mode=S_IFREG|0644, st_size=4, ...}) = 0
stat("/tmp/test/aminglinux.txt", {st_mode=S_IFREG|0644, st_size=4, ...}) = 0
access("/tmp/test/aminglinux.txt", W_OK) = 0
write(1, ""aminglinux.txt"", 16) = 16
stat("aminglinux.txt", {st_mode=S_IFREG|0644, st_size=4, ...}) = 0
access("aminglinux.txt", W_OK) = 0
getxattr("aminglinux.txt", "system.posix_acl_access", 0x7fff49efd050, 132) = -1 ENODATA (No data available)
stat("aminglinux.txt", {st_mode=S_IFREG|0644, st_size=4, ...}) = 0
open("aminglinux.txt", O_WRONLY|O_CREAT|O_TRUNC, 0644) = 3
chmod("aminglinux.txt", 0100644) = 0
setxattr("aminglinux.txt", "system.posix_acl_access", "x02x00x00x00x01x00x06x00xffxffxffxffx04x00x04x00xffxffxffxff x00x04x00xffxffxffxff", 28, 0) = 0
stat("/tmp/test/aminglinux.txt", {st_mode=S_IFREG|0644, st_size=6, ...}) = 0
unlink("/var/tmp/aminglinux.txt.swp") = 0
我相信你可以看到Permission denied的提示,這是因為當前目錄有i許可權,不能增加檔案,也就不能在當前目錄下生成臨時檔案。當然,vim如果遇到這樣的問題,它還是會“曲線救國”的,於是先找/root/tmp/,但是並沒有該目錄,只好繼續找/var/tmp/,這個目錄存在,所以就在這個目錄裡生成了臨時檔案(並不是隱藏的)。後面的操作就不用多說了。
既然vim可以在/var/tmp/下生成臨時檔案,自然也可以在已經設定了i許可權的目錄裡編輯檔案的,這樣現象2也解釋通了。上面羅嗦了這麼多,其實我就想表達如下觀點:
vim編輯檔案時,會在該檔案所在目錄生成臨時隱藏檔案.swp和.swx,如果那目錄不可寫就會到/root/tmp/下或者/var/tmp/下生成臨時檔案(非隱藏),當編輯的檔案儲存後,臨時檔案刪除。