如何在Unix中交换文件名?

任何方式快速做到这一点,而不使用临时variables? 有内置function吗?

编辑:谢谢你的答案。 看起来我需要澄清我的问题,但在大多数情况下,你们假设正确:有两个文件和文件名称是相反的。

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

我想将文件A命名为A-name.file,将文件B命名为B-name.file。

我同意,情况不是经常发生,但它只是发生在我身上,我想快速修复。

好的,愚蠢的问题,但为什么你不能简单地做一些像(在shell脚本):

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

当然是使用临时文件,但是其他答案更简洁。

达尔文/ Mac OS X有exchangedata()系统调用:

exchangedata()函数以原子方式交换由path1path2引用的文件的内容。 也就是说,所有并发进程将看到预交换状态或后交换状态; 他们永远不会看到处于不一致状态的文件。

然而,它只能在一些专门支持它的文件系统上工作(比如苹果的HFS和HFS +),而在其他系统上我没有看到类似的系统调用。 可移植的方式是使用第三个临时文件名,操作不会是原子操作。

这可以用小帮手完成,只需放入.bashrc,.zshrc或你的配置。

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

并将其用作常规功能:

 $ cat ab Alfa Beta $ swap ab && cat ab Beta Alfa 

在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和$ file2在同一个文件系统上(并且我假设$ file3是同一个文件系统上的一个名字),那么这是一个半正式的近似值。 固定它来处理所有的疣是…不平凡的。 (考虑$ file1 == $ file2,例如。)

代码几乎模拟了C程序必须进行的系统调用,以便映射到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); 

什么“交换文件名”是什么意思? 你是在谈论文件系统,还是只是在你的程序中的变量?

如果你的程序是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中有新的数据,在tempfile中有旧数据(但不是newfile!)