如果我有一個命令
$ ./script >> file.log
被呼叫兩次,第二次呼叫發生在第一個呼叫結束之前,會發生什麼事?
第一次呼叫是否獲得輸出檔的獨佔鎖?如果是這樣,第二個腳本在嘗試寫入時是否會失敗,或者 shell 是否接受輸出(允許腳本結束)並拋出錯誤?
或是日誌檔案是否被寫入兩次?
答案1
Unix 系統整體避免強制鎖。在某些情況下,核心會鎖定檔案以防止使用者程式修改,但如果檔案只是由另一個程式寫入,則不會。沒有 UNIX 系統會因為程式正在寫入檔案而鎖定檔案。
如果您希望腳本的並發實例不互相打擾,則需要使用明確鎖定機制,例如flock
lockfile
。
當您開啟檔案進行追加時(確實>>
如此),每個程式都保證始終寫入檔案的末端。因此,多個實例的輸出永遠不會互相覆蓋,如果它們輪流寫入,它們的輸出將與寫入的順序相同。
可能發生的壞事是,如果其中一個實例寫入了多個輸出區塊並期望它們一起輸出。在一個實例的連續寫入之間,其他實例可以執行自己的寫入。例如,如果實例 1 寫入foo
,然後實例 2 寫入hello
,然後只有實例 2 寫入bar
,則該檔案將包含foohellobar
.
當進程呼叫系統呼叫時,它會有效地寫入檔案write
。對 的呼叫write
是原子的:每次呼叫都會write
寫入不會被其他程式中斷的位元組序列。單次呼叫有效寫入的資料量通常有限制write
:對於較大的大小,僅寫入資料的開頭,應用程式必須write
再次呼叫。此外,許多程式執行緩衝:它們在記憶體區域中累積數據,然後將這些數據寫入一個區塊中。某些程式在完成行或其他有意義的分隔後會刷新輸出緩衝區。使用此類程序,您可以期望整行不間斷,只要它們不太長(最多幾千位元組;這取決於作業系統)。如果程式不在有意義的位置刷新,而僅根據緩衝區大小進行刷新,您可能會看到一個實例中的4kB,然後是另一個實例中的4kB,然後又是第一個實例中的4kB,依此類推。
答案2
由於您使用的是>>
,這意味著附加,因此每個實例的每一行輸出都將按照其發生的順序附加。
如果您的腳本輸出1\n
在5\n
每次列印之間有 1 秒的延遲,且實例 2 在 2.5 秒後啟動,您將得到以下結果:
1
2
1
3
2
4
3
5
4
5
所以回答你的問題:不。