2009-12-31 31 views
5

Bất kỳ cách nào để thực hiện điều này một cách nhanh chóng mà không sử dụng biến tạm thời? Có chức năng tích hợp không?Làm thế nào để trao đổi tên tập tin trong Unix?

Chỉnh sửa: Cảm ơn các bạn đã trả lời. Có vẻ như tôi cần phải làm rõ câu hỏi của mình nhưng đối với hầu hết các phần, các bạn đã giả định chính xác: Có hai tệp và tên tệp được đảo ngược.

  • file A có tên B-name.file
  • file B có tên A-name.file

Tôi muốn cho File A được đặt tên là A-name.file và File B được đặt tên là B-name.file.

Tôi đồng ý, tình huống này không xảy ra thường xuyên nhưng nó chỉ xảy ra với tôi và tôi muốn sửa chữa nhanh chóng.

+0

Ý anh là gì bằng cách trao đổi tên tập tin? Đổi tên tệp "A" thành "B" và v.v.? – Kimvais

+0

Không có chức năng tích hợp cho JUST hoán đổi tên tập tin! như bạn đã nói, bạn có thể làm điều đó bằng một kịch bản lệnh shell và biến tạm thời –

+1

Bạn có một ngôn ngữ triển khai cụ thể hay bạn cần một lệnh (shell)? Loại phân vùng nào đang được sử dụng? (Không làm việc trên NFS cần phải được xem xét?) Có gì sai với các approp biến tạm thời? –

Trả lời

4

ok, câu hỏi ngu ngốc, nhưng tại sao có thể không chỉ đơn giản là bạn làm điều gì đó tương tự (trong một kịch bản shell):

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

và vâng tất nhiên nó sử dụng một tệp tạm thời, nhưng ngắn gọn hơn thì các câu trả lời khác.

+4

Nó sử dụng một tên tệp tạm thời, nhưng ít nhất không có sao chép đang diễn ra. –

3

Ở cấp tập lệnh shell - không có lệnh tiêu chuẩn và việc đổi tên liên quan đến ít nhất một tên tệp tạm thời (hãy coi các tệp phần mềm trên các hệ thống tệp khác nhau!).

Ở cấp mã C, không có chức năng chuẩn trên tất cả các máy để trao đổi tên tệp - và một trong các yếu tố là vấn đề xử lý tệp trên các hệ thống tệp khác nhau.

Trên một hệ thống tập tin duy nhất:

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 

Đó không phải là hoàn toàn fool-proof - nhưng nó là một xấp xỉ bán đàng hoàng nếu $ file1 file2 và $ là trên hệ thống tập tin tương tự (và tôi đã giả định $ file3 là tên trên cùng một hệ thống tệp). Sửa chữa nó để đối phó với tất cả các mụn cóc là ... không tầm thường. (. Xem xét $ file1 file2 == $, ví dụ)

Mã này mô phỏng khá nhiều hệ thống gọi là một chương trình C sẽ phải làm - ln để ánh xạ link()rm để ánh xạ unlink(). Chức năng mới hơn (như trong, chỉ hai mươi tuổi) rename() có thể được sử dụng để có hiệu quả tốt - miễn là bạn hiểu nó sẽ không làm gì. Sử dụng lệnh mv thay vì liên kết và xóa có nghĩa là các tệp sẽ được di chuyển giữa các hệ thống tệp nếu cần; điều đó có thể hữu ích - hoặc nó có thể có nghĩa là không gian đĩa của bạn lấp đầy khi bạn không có ý định. Phục hồi từ một phần lỗi thông qua là không hoàn toàn tầm thường, một trong hai.

1

Có lẽ nó có thể được thực hiện với:

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); 

Có thể là một cách (Tôi đang tìm kiếm thông qua spec POSIX để xem, nhưng tôi sẽ không đặt cược vào nó) để tạo ra một hardlink từ số inode; mà sẽ kết thúc làm một cái gì đó giống như

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

Nếu tệp B là vài gigabyte, điều đó sẽ rất chậm. Tại sao di chuyển dữ liệu tùy ý khi bạn chỉ có thể trộn các mục nhập thư mục? – fennec

+0

Vì anh ta không muốn một tên tập tin tạm thời. Đó là một hạn chế ngớ ngẩn, nhưng đó là một phần của câu hỏi. – Tordek

+1

Đó là sự thật. Câu hỏi "tại sao di chuyển dữ liệu tùy ý" của tôi chủ yếu là tu từ; tuy nhiên, trong khi điều này thực sự là một giải pháp trong hạn chế ngớ ngẩn, có vẻ như có khả năng xảy ra các vấn đề về hiệu suất, vì vậy chúng tôi có lẽ ít nhất phải mô tả những hàm ý này và đề xuất với các bên liên quan có ràng buộc xem xét lại. :) – fennec

1

"Tên tệp hoán đổi" có nghĩa là gì? Bạn đang nói về hệ thống tập tin, hay chỉ là các biến trong chương trình của bạn?

Nếu chương trình của bạn là C++ và bạn có hai tên tệp trong chuỗi và muốn trao đổi chúng, hãy sử dụng std :: swap.Điều này chỉ thay đổi các biến trong chương trình:

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

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

Nếu bạn có hai tập tin trên đĩa, và bạn muốn những cái tên để trao đổi nội dung với nhau, thì không có, không có cách nào để dễ dàng vào đó, nếu bạn muốn giữ liên kết cứng. Nếu bạn chỉ muốn thực hiện "lưu an toàn" thì lệnh gọi hệ thống unix rename() sẽ ghi đè tệp đích bằng tệp nguồn trong một hoạt động nguyên tử (như nguyên tử có thể được hệ thống tệp cơ bản hỗ trợ). Do đó, bạn sẽ an toàn lưu như sau:

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

Nếu bạn thực sự cần trao đổi tệp trên đĩa (để giữ bản sao lưu), hãy nhập liên kết cứng. Lưu ý: liên kết cứng không được hỗ trợ trên tất cả các hệ thống tệp (cụ thể là một số chia sẻ tệp SMB), vì vậy bạn cần triển khai một số bản sao lưu nếu cần. Bạn sẽ cần một tệp tạm thời tên, nhưng không cần bất kỳ kho lưu trữ dữ liệu tạm thời nào. Trong khi bạn có thể thực hiện nó bằng tay với liên kết() và bỏ liên kết() (nhớ: các tập tin có thể có nhiều liên kết cứng trong UNIX), nó dễ dàng hơn chỉ bằng cách sử dụng rename(). Tuy nhiên, bạn không thể hoán đổi một cách nguyên tử.

giả oldfile là "filname.dat" và newFile là "filename.dat.bak" bạn sẽ có được điều này:

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

Nếu bạn sụp đổ sau khi liên kết, bạn sẽ có dữ liệu mới trong newfile, và dữ liệu cũ trong oldfile và tempfile. Nếu bạn sụp đổ sau khi đổi tên đầu tiên, bạn sẽ có dữ liệu mới trong oldfile, và các dữ liệu cũ trong tempfile (nhưng không newFile!)

8

Darwin/Mac OS X có cuộc gọi exchangedata() hệ thống:

Chức năng exchangedata() hoán đổi nội dung của các tệp được tham chiếu bằng đường dẫn1đường dẫn theo kiểu nguyên tử. Nghĩa là tất cả các quy trình đồng thời sẽ thấy trạng thái được trao đổi trước hoặc trạng thái được trao đổi sau; họ không bao giờ có thể thấy các tệp ở trạng thái không nhất quán.

Tuy nhiên, nó chỉ thực sự hoạt động trên một vài hệ thống tệp hỗ trợ đặc biệt (như HFS và HFS + của Apple) và tôi chưa thấy bất kỳ cuộc gọi hệ thống tương tự nào trên các hệ thống khác. Cách di động để thực hiện việc này là sử dụng tên tệp tạm thời thứ ba và thao tác sẽ không phải là nguyên tử.

5

Điều này có thể được thực hiện với trợ giúp nhỏ, chỉ cần nhập .bashrc, .zshrc hoặc nơi cấu hình của bạn.

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

Và sử dụng nó như là chức năng thường xuyên:

$ cat a b 
Alfa 
Beta 

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

Giải pháp này là cách dễ nhất và gần nhất với câu hỏi. –

Các vấn đề liên quan