2009-12-31 75 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