Cp

對帶有硬連結的 cp 的行為感到驚訝

  • September 8, 2015

我非常了解硬連結的概念,並且已經多次閱讀基本工具的手冊頁cp——甚至是最近的 POSIX 規範——。我仍然驚訝地觀察到以下行為:

$ echo john > john
$ cp -l john paul
$ echo george > george

此時johnpaul將具有相同的 inode(和內容),並且george在兩個方面都會有所不同。現在我們這樣做:

$ cp george paul

在這一點上,我期望georgeandpaul有不同的 inode 編號但內容相同 — 這個期望已經實現 — 但我期望paul現在有一個不同的 inode 編號john,並且john仍然有內容john。這就是我感到驚訝的地方。事實證明,將文件複製到目標路徑paul也會導致在共享 的 inode 的所有其他目標路徑上安裝相同的文件(相同paul的 inode)。我在想cp創建一個新文件並將其移動到以前由舊文件佔用的位置paul。相反,它似乎做的是打開現有文件paul,截斷它,然後寫george的內容到該現有文件中。因此,任何具有相同 inode 的“其他”文件都會同時更新“它們的”內容。

好的,這是一種系統行為,現在我知道可以預期它,我可以弄清楚如何解決它,或者酌情利用它。令我困惑的是,我應該在哪裡看到這種行為的記錄?如果它沒有記錄在我已經看過的文件中的*某個地方,我會感到驚訝。*但顯然我錯過了它,現在找不到討論這種行為的來源。

cp如果目標文件已經存在,它會覆蓋目標文件。沒錯,它沒有詳細說明“覆蓋”的含義,但它肯定說的是“覆蓋”,而不是“替換”。如果您想學究氣,您可以爭辯說“覆蓋”正是這樣cp做的,而您所期望的行為將被正確地稱為“替換”。

另請注意,如果cp要“替換”預先存在的目標文件,這可能會被認為是令人驚訝或不正確的,可能比“覆蓋”更重要。例如:

  • 如果cp先刪除舊文件,然後創建一個新文件,那麼會有一段時間該文件不存在,這將是令人驚訝的。
  • 如果cp首先創建了一個臨時文件,然後將其移動到位,那麼它可能應該記錄這一點,因為這種具有奇怪名稱的臨時文件偶爾會被注意到……但事實並非如此。
  • 如果cp由於權限而無法在與舊文件相同的目錄中創建新文件,那麼這將是不幸的(特別是如果它已經刪除了舊文件)。
  • 如果該文件不屬於正在執行cp的使用者並且正在執行的使用者cp不屬於該文件,root那麼就不可能將新文件的所有者和權限與新文件的所有者和權限相匹配。
  • cp如果文件具有不知道的特殊屬性,那麼這些將在副本中失去。現在的實現cp應該可靠地理解擴展屬性之類的東西,但並非總是如此。還有其他東西,比如 MacOS 資源分叉,或者,對於遠端文件系統,基本上任何東西。

總而言之:現在您知道cp真正的作用了。你再也不會對它感到驚訝了!老實說,我想同樣的事情也可能發生在我身上,很多年前。

我看到 POSIX 2013 標準確實指定了觀察到的行為。它說:

  1. 如果source_file是正常文件類型,應採取以下步驟:

一種。… 如果dest_file存在,則應採取以下步驟:

一世。如果該-i選項有效,cp實用程序將向標準錯誤寫入提示並從標準輸入中讀取一行。如果響應不是肯定的,則cp不應再對 source_file執行任何操作並繼續處理任何剩餘的文件。

ii. dest_file的文件描述符應通過執行open()與 POSIX.1-2008 的系統介面卷中定義的函式等效的操作來獲得,該函式使用dest_file作為路徑參數,按位包含ORO_WRONLY作為O_TRUNCoflag參數

iii. 如果獲取文件描述符的嘗試失敗並且該-f選項有效,則應嘗試通過執行與使用dest_file作為路徑參數呼叫的 POSIX.1-2008 系統介面卷中定義cp的函式等效的操作來刪除文件。如果此嘗試成功,則應繼續執行步驟 3b。unlink()``cp

d。source_file的內容應寫入文件描述符。任何寫入錯誤都會導致cp將診斷消息寫入標準錯誤並繼續執行步驟 3e。

e. 文件描述符應關閉。

引用自:https://unix.stackexchange.com/questions/226910