2009-12-31 76 views
5

任何方式快速做到這一點,而不使用臨時變量?是否有內置函數?如何在Unix中交換文件名?

編輯:謝謝你們的答案。看起來我需要澄清我的問題,但大多數情況下你們都假設正確:有兩個文件,文件名稱是相反的。

  • 文件具有名B-name.file
  • 文件B具有名A-name.file

我想對文件被命名爲A-name.file和文件B被命名爲B-name.file。

我同意,情況不會經常發生,但它只是發生在我身上,我想快速修復。

+0

你說的交換文件名是什麼意思?將文件「A」重命名爲「B」和v.v.? – Kimvais 2009-12-31 22:18:47

+0

JUST交換文件名沒有內置函數!正如你所說的,你可以通過shell腳本和一個臨時變量來完成 – 2009-12-31 22:21:47

+1

你有具體的實現語言,還是需要(shell)命令?正在使用什麼類型的分區? (是否需要考慮NFS的工作?)臨時變量approarch有什麼問題? – 2009-12-31 22:23:16

回答

4

OK,愚蠢的問題,但你爲什麼不能簡單地這樣做(在shell腳本):

mv $fileA $fileA.$$ 
mv $fileB $fileA 
mv $fileA.$$ $fileB 

和是的,當然它採用的是臨時文件,但它更簡潔,然後其他答案。

+4

它使用臨時文件名,但至少沒有複製正在進行。 – 2009-12-31 22:52:15

3

在shell腳本級別 - 沒有標準命令,重命名至少包含一個臨時文件名(注意不同文件系統上的文件!)。

在C代碼級別,所有計算機上都沒有標準函數來交換文件名 - 其中一個因素是處理不同文件系統上的文件的問題。

在一個單一的文件系統:

file1=one-file-name 
file2=tother-file 
file3=tmp.$$ 

trap "" 1 2 3 13 15 
ln $file1 $file3 
rm $file1 
ln $file2 $file1 
rm $file2 
ln $file3 $file2 
rm $file3 
trap 1 2 3 13 15 

這不完全是傻瓜式的證明 - 但它是一個半體面的逼近,如果$ file1和$文件2是相同的文件系統上(和我」我們假設$ file3是同一文件系統上的一個名稱)。固定它來處理所有的疣是...不平凡的。 (考慮$文件1 == $文件2,例如)

代碼模擬相當多的系統調用,一個C程序將不得不作出 - ln映射到link()rm映射到unlink()。如果你明白它不會做什麼,那麼較新的(如只有二十歲的)功能rename()可能會被用來取得良好的效果。使用mv命令而不是鏈接和刪除意味着文件將在需要時在文件系統之間移動;這可能會有所幫助 - 或者這可能意味着您的磁盤空間在您無意使用時會填滿。從部分錯誤中恢復並不是完全微不足道的。

1

也許可以用做:

file_B = fopen(path_b, 'r'); 
rename(path_a, path_b); 

file_B_renamed = fopen(path_a, 'w'); 
/* Copy contents of file_B into file_B_renamed */ 
fclose(file_B_renamed); 
fclose(file_B); 

有可能是一個辦法(我在尋找通過POSIX規範看到的,但我不會賭)創建一個從硬鏈接inode編號;這最終會做這樣的事情

file_B = fopen(path_b, 'r'); 
rename(path_a, path_b); 
make_hardlink(file_B, path_a); 
+0

如果文件B是幾千兆字節,那會非常慢。爲什麼在可以將目錄條目洗牌時移動任意數據? – fennec 2009-12-31 22:21:13

+0

因爲他不想要臨時文件名。這是一個愚蠢的約束,但這是問題的一部分。 – Tordek 2009-12-31 22:31:15

+1

的確如此。我的「爲什麼要移動任意數據」的問題大多是修辭性的;然而,雖然這確實是一個愚蠢約束下的解決方案,但它似乎可能與性能問題相抵觸,因此我們可能至少應該描述這些影響,並向相關利益相關者建議重新考慮約束條件。 :) – fennec 2009-12-31 22:49:50

1

「swap文件名」是什麼意思?你是在談論文件系統,還是隻是在你的程序中的變量?

如果你的程序是C++,並且你有兩個文件名在字符串中,並且想交換它們,請使用std :: swap。這不僅改變了程序中的變量:

std::string filenameA("somefilename"); 
std::string filenameB("othername"); 

std::swap(filenameA, filenameB); 
std::cout << filenameA << std::endl; // prints "othername" 

如果磁盤上有兩個文件,和你想要的名稱交換內容與對方的話沒有,有沒有辦法來容易,如果你想保留硬鏈接。如果你只是想執行一個「安全保存」,那麼unix rename()系統調用會在原子操作中將目標文件與源文件一起打開(原子操作可能由底層文件系統支持)。因此,你會安全保存這樣的:

std::string savename(filename); 
savename += ".tmp"; 
... write data to savename ... 
if (::rename(savename.c_str(), filename.c_str()) < 0) { 
    throw std::exception("oops!"); 
} 

如果你真的,真的需要交換磁盤上的文件(比如說,保留的備份副本),然後輸入硬鏈接。注意:所有文件系統(特別是某些SMB文件共享)都不支持硬鏈接,因此如果需要,您需要實施一些備份。您將需要一個臨時文件名稱,但不是任何臨時數據存儲。雖然你可以用link()和unlink()手動實現它(記住:UNIX中的文件可以有多個硬鏈接),但使用rename()會更容易。儘管如此,你無法完全原子地進行交換。

假設的oldfile是「filname.dat」和newfile中是「filename.dat.bak」你會得到這樣的:

::link(oldfile, tempfile); 
::rename(newfile, oldfile); 
::rename(tempfile, newfile); 

如果您鏈接之後崩潰,你就會有新的數據newfile和oldfile和tempfile中的舊數據。 如果第一重命名後崩潰,你必須在的oldfile在臨時文件的新數據和舊數據(而不是NEWFILE!)

8

達爾文/ Mac OS X上有exchangedata()系統調用:

exchangedata()函數以原子方式交換path1path2引用的文件的內容。也就是說,所有併發進程都將看到預交換狀態或後交換狀態;他們永遠不會看到處於不一致狀態的文件。

然而,它只能在一些特別支持它的文件系統(如Apple的HFS和HFS +)上實際工作,而且我在其他系統上沒有看到任何類似的系統調用。可移植的方法是使用第三個臨時文件名,並且該操作不會是原子操作。

5

這可以用小幫手完成,只需放入.bashrc,.zshrc或您的配置。

function swap() { mv $1 $1._tmp && mv $2 $1 && mv $1._tmp $2 } 

而且使用它作爲常規功能:

$ cat a b 
Alfa 
Beta 

$ swap a b && cat a b 
Beta 
Alfa 
+0

該解決方案是最容易和最接近問題的解決方案。 – 2015-07-23 07:08:36