如果檔案被移動或刪除,開啟的檔案控制代碼會發生什麼?
概述
我們將瞭解當我們刪除、移動或替換具有開啟控制代碼的檔案時,作業系統的行為方式。
我們首先簡要介紹一下檔案和inode。之後,我們將檢視不同的場景,並瞭解每種情況下會發生哪種情況。
理解檔案和inode
儲存在 Linux 檔案系統上的檔案使用 inode 編號來跟蹤其內容。
我們通常透過列出其檔名(連結)然後列出其對應的 inode 編號(硬連結)來列出目錄的內容。
我們可以對檔案使用 stat 並檢視它引用哪個 inode -
$ touch inode_example $ stat inode_example File: inode_example Size: 0 Blocks: 0 IO Block: 4096 regular empty file Device: fd03h/64771d Inode: 20448632 Links: 1
此檔案連結到 inode 204488632,並且 stat 還顯示有一個連結。讓我們新增一個新的硬連結檔案並再次在其上執行 stat。
$ ln inode_example hardlink_inode_example $ stat inode_example File: inode_example Size: 0 Blocks: 0 IO Block: 4096 regular empty file Device: fd03h/64771d Inode: 20448632 Links: 2
我們可以看到每個連結在其 URL 中都添加了一個增量值。我們現在也可以對 hardlink_inode_example 使用 stat -
$ stat hardlink_inode_example File: hardlink_inode_example Size: 0 Blocks: 0 IO Block: 4096 regular empty file Device: fd03h/64771d Inode: 20448632 Links: 2
與共享 inode 編號的硬連結不同,符號連結的 inode 編號與父目錄分開。
刪除檔案
每次我們建立新連線時,都會生成一個新程序。每個程序都有一個關聯的記憶體空間,資料儲存在其中。為了訪問資料,作業系統必須將地址轉換為記憶體空間內的物理位置。
讓我們建立一個名為 remove_opened_file 的 shell 檔案來測試我們的想法。
#!/bin/bash FILE="/tmp/remove_example" ( sleep 1 echo "Before rm." >&4 rm "$FILE" if [ ! -e "$FILE" ]; then echo "The file $FILE was removed." fi echo "After rm." >&4 ) 4>"$FILE" & ( sleep 2 echo "This is the content in file handle 4:" cat <&4 ) 4<"$FILE"
我們首先啟動兩個子 shell,然後我們使用重定向在每個子 shell 中建立和訪問 /tmp/remove_examples 作為檔案控制代碼 4。當子 shell 終止時,系統會關閉檔案控制代碼。
讓我們執行它並檢查它是否有效。
$ ./remove_opened_file.sh The file /tmp/remove_example was removed. This is the content in file handle 4: Before rm. After rm.
當我們刪除目錄時,我們實際上並沒有刪除其中的檔案;相反,我們只是刪除了檔名和 inode 之間的連結。因此,儘管檔案本身消失了,但它們仍然可以透過其 inode 訪問。
當系統刪除 inode 時,它會刪除其內容。
沒有更多指向它的硬連結
沒有開啟的檔案控制代碼
刪除檔案並不一定意味著可用磁碟儲存空間減少
移動檔案
系統有兩種方法可以將檔案從一個位置傳輸到另一個位置 -
重新命名檔案
將其內容複製到目標,然後刪除源
根據具體情況,程式會使用一種或另一種方法。例如,如果我們正在將檔案從一個位置複製到另一個位置,那麼程式可能會使用 Copy 命令。
檔案被重新命名
如果更改了原始檔名,則不會影響開啟的檔案。我們仍然可以寫入和讀取它們。由於 inode 相同,因此我們在移動後寫入的內容將寫入新位置。
讓我們編寫 move_open_file.sh 來測試移動開啟的檔案。
#!/bin/bash FILE=/tmp/move_example FILE_NEW=/tmp/move_example.new ( echo "Before mv." >&4 mv "$FILE" "$FILE_NEW"; if [ ! -e "$FILE" -a -e "$FILE_NEW" ]; then echo "The file $FILE was moved to $FILE_NEW." fi echo "After mv." >&4 echo "This is the content in $FILE_NEW:" cat "$FILE_NEW" ) 4>"$FILE"
在這裡,我們使用子 shell 和重定向,就像我們在上一個示例中所做的那樣。我們首先建立一個開啟的檔案控制代碼以寫入輸出檔案。然後,我們執行 mV 命令。
我們可以看出檔案是從相同位置複製的,因為它們具有相同的名稱。現在讓我們看看是否可以更改其名稱。
檔案 /tmp/move_example 已移動到 /tmp/move_example.new。
檔案被複制
當系統將源文件複製到目標位置時,不會保留源文件的原始內容。相反,副本僅包含源文件中包含的資訊。源文件關閉後,對源文件所做的任何更改都會丟失。
現在我們需要修改我們的 move_opened_files.sh 指令碼,以便目標位於單獨的檔案系統中。通常 /tmp 和 /home 位於不同的檔案系統中。結果如下 -
檔案 /tmp/move_example 已移動到 /home/baeldung/move_by_copy_example.new。
這是 /home/baeldung/move_by_copy_example.new 中的內容 -
Before mv.
替換檔案
當程式的新版本替換舊版本時,系統會刪除程式的舊版本。這意味著我們可以繼續使用舊版本的軟體,直到我們關閉應用程式的視窗。
我們可以編寫一個名為 replace_opened_file 的 shell 指令碼,該指令碼測試是否已將開啟的檔案替換為另一個檔案。
#!/bin/bash FILE=/tmp/replace_example FILE_OLD=/tmp/replace_example.old echo "This is the old file." > $FILE_OLD ( sleep 1 echo "Before mv." >&4 mv "$FILE_OLD" "$FILE" echo "After mv." >&4 ) 4>"$FILE" & ( sleep 2 echo "This is the content in file handle 4:" cat <&4 echo "This is the content in $FILE:" cat $FILE ) 4<"$FILE"
在此指令碼中,讓我們首先建立同一文件的舊版本。然後我們開啟一個新的 shell 並將同一文件的新版本寫入其中。最後,我們列印新寫入的文件的內容。
讓我們執行 replace_opened_file。
$ ./replace_opened_file.sh
這是檔案控制代碼 4 中的內容 -
Before mv. After mv.
結論
我們研究了當我們刪除檔案、複製檔案或更改其位置時會發生什麼。
我們看到我們可以刪除或替換單個文件,並且我們仍然可以使用其開啟的文件控制代碼訪問它,即使我們已刪除或替換它。
一方面,我們看到如果我們將檔案移動到同一目錄中,則開啟的控制代碼將指向新檔案。但是,如果我們將其移動到另一個目錄,則開啟的檔案將指向舊檔案。