任何方式快速做到這一點,而不使用臨時變量?是否有內置函數?如何在Unix中交換文件名?
編輯:謝謝你們的答案。看起來我需要澄清我的問題,但大多數情況下你們都假設正確:有兩個文件,文件名稱是相反的。
- 文件具有名B-name.file
- 文件B具有名A-name.file
我想對文件被命名爲A-name.file和文件B被命名爲B-name.file。
我同意,情況不會經常發生,但它只是發生在我身上,我想快速修復。
任何方式快速做到這一點,而不使用臨時變量?是否有內置函數?如何在Unix中交換文件名?
編輯:謝謝你們的答案。看起來我需要澄清我的問題,但大多數情況下你們都假設正確:有兩個文件,文件名稱是相反的。
我想對文件被命名爲A-name.file和文件B被命名爲B-name.file。
我同意,情況不會經常發生,但它只是發生在我身上,我想快速修復。
OK,愚蠢的問題,但你爲什麼不能簡單地這樣做(在shell腳本):
mv $fileA $fileA.$$
mv $fileB $fileA
mv $fileA.$$ $fileB
和是的,當然它採用的是臨時文件,但它更簡潔,然後其他答案。
它使用臨時文件名,但至少沒有複製正在進行。 – 2009-12-31 22:52:15
在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
命令而不是鏈接和刪除意味着文件將在需要時在文件系統之間移動;這可能會有所幫助 - 或者這可能意味着您的磁盤空間在您無意使用時會填滿。從部分錯誤中恢復並不是完全微不足道的。
也許可以用做:
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);
「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!)
達爾文/ Mac OS X上有exchangedata()
系統調用:
exchangedata()
函數以原子方式交換path1和path2引用的文件的內容。也就是說,所有併發進程都將看到預交換狀態或後交換狀態;他們永遠不會看到處於不一致狀態的文件。
然而,它只能在一些特別支持它的文件系統(如Apple的HFS和HFS +)上實際工作,而且我在其他系統上沒有看到任何類似的系統調用。可移植的方法是使用第三個臨時文件名,並且該操作不會是原子操作。
這可以用小幫手完成,只需放入.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
該解決方案是最容易和最接近問題的解決方案。 – 2015-07-23 07:08:36
你說的交換文件名是什麼意思?將文件「A」重命名爲「B」和v.v.? – Kimvais 2009-12-31 22:18:47
JUST交換文件名沒有內置函數!正如你所說的,你可以通過shell腳本和一個臨時變量來完成 – 2009-12-31 22:21:47
你有具體的實現語言,還是需要(shell)命令?正在使用什麼類型的分區? (是否需要考慮NFS的工作?)臨時變量approarch有什麼問題? – 2009-12-31 22:23:16