Cách tốt nhất để trao đổi tên tập tin


8

Tôi cần hoán đổi tên tập tin của hai tập tin ( filefile_1). Tôi đang sử dụng mã sau đây cho nó.

mv file .phfile
mv file_1 file
mv .phfile file

Điều này hoạt động nhưng rất có lỗi, đôi khi nó thậm chí dẫn đến mất dữ liệu. Có cách nào tốt hơn để làm điều này?


5
Một cái gì đó bạn nên chú ý và sợ hãi - bất kỳ chương trình nào có tệp xử lý mở đối với một trong các tệp đó sẽ giữ lại phần xử lý tệp đang mở sau khi đổi tên vì nó trỏ đến cùng một nút mà nó có khi ban đầu mở tệp. Cho đến khi tất cả các chương trình có các tệp mở đóng chúng, đây sẽ là trường hợp và gây ra hỏng dữ liệu nếu bạn cho rằng việc đổi tên chúng 'phá vỡ' bất kỳ nhà văn hiện có nào xử lý.
tổng

Câu trả lời:


4

Tòa nhà renameat2trên các hệ thống Linux, với RENAME_EXCHANGEcờ, nên thực hiện chính xác điều đó, đây là một công cụ cli tuyên bố sẽ sử dụng nó.


Rằng đây không phải là câu trả lời đúng được chọn là hình sự.
Xaekai


@Xaekai Hyperbole sang một bên, không. Tính năng đó thậm chí không tồn tại khi câu hỏi được hỏi và thậm chí ngày nay nó chỉ hoạt động trên Linux, không phải trên các hệ điều hành khác và nó yêu cầu một tiện ích mà bạn không có khả năng đã cài đặt.
Gilles 'SO- ngừng trở nên xấu xa'

@ Gilles'SO-stopbeingevil 'Bằng chính sự lịch sự của di sản UNIX, tôi có thể lấy ý chính đó, biên dịch nó, mv nó vào một thư mục trong PATH của tôi, chmod + x và gọi nó trong chưa đầy 40 giây. Giết quan điểm của bạn với định kiến. Ngoài ra, chúng tôi bây giờ đã 8 năm sau và dường như tòa nhà này đã 7 tuổi 🤷 Tôi hy vọng phần lớn đến đây là trên nhân Linux, vì OSX có thể là UNIX hợp pháp nhưng chắc chắn không phải là tinh thần, và thị trường sống của BSD- trong không gian người dùng gần như không còn nữa.
Xaekai

3

Không có cách nào thấp để trao đổi các tệp trong các hệ thống Unix truyền thống, vì vậy bạn cần sử dụng tên tạm thời trung gian. Để chắc chắn, hãy đảm bảo rằng tên tạm thời sẽ không được sử dụng bởi bất kỳ chương trình nào khác (vì vậy sử dụng mktemp) và nó trên cùng một hệ thống tệp với một trong các tệp (nếu không các tệp sẽ được sao chép một cách không cần thiết thay vì chỉ được đổi tên).

swap_files () {
  tmp_name=$(TMPDIR=$(dirname -- "$1") mktemp) &&
  mv -f -- "$1" "$tmp_name" &&
  mv -f -- "$2" "$1" &&
  mv -f -- "$tmp_name" "$1"
}
swap_files file file_1

Xin lưu ý rằng nếu xảy ra lỗi, tệp đầu tiên vẫn có thể nằm dưới tên tạm thời và tệp thứ hai có thể hoặc chưa được di chuyển. Nếu bạn cần sự mạnh mẽ trong trường hợp bị gián đoạn và gặp sự cố, một biến thể có hai tên tạm thời có thể dễ dàng phục hồi hơn.

swap_files2 () {
  tmp_dir1=$(TMPDIR=$(dirname -- "$1") mktemp -d .swap_files.XXXXXXXXXXXX) &&
  tmp_dir2=$(TMPDIR=$(dirname -- "$2") mktemp -d .swap_files.XXXXXXXXXXXX) &&
  mv -f -- "$1" "$tmp_dir1/" &&
  mv -f -- "$2" "$tmp_dir2/" &&
  mv -f -- "$tmp_dir1/"* "$1" &&
  mv -f -- "$tmp_dir2/"* "$2" &&
  rmdir -- "$tmp_dir1" "$tmp_dir2"
}

Nếu các thư mục tạm thời .swap_files.????????????có mặt khi khởi động lại, điều đó có nghĩa là việc hoán đổi tập tin bị gián đoạn do mất điện. Xin lưu ý rằng có thể một trong các tệp đã được chuyển vào vị trí còn tệp kia thì không, vì vậy mã ở đây không quan tâm đến tất cả các trường hợp, nó phụ thuộc vào loại phục hồi bạn muốn.

Các hạt nhân Linux hiện đại (kể từ 3.15, được phát hành lại vào tháng 6 năm 2014) có một cuộc gọi hệ thống để trao đổi các tệp : renameat2(…, RENAME_EXCHANGE). Tuy nhiên, dường như không có tiện ích dòng lệnh phổ biến nào cho nó. Ngay cả hỗ trợ glibc chỉ được thêm vào gần đây ( 2.28 , được phát hành vào tháng 8 năm 2018).


cách dễ dàng thực sự: D
Kiwy

"Không có cách nào để trao đổi tập tin ở mức độ thấp" dường như không đúng, xem unix.stackexchange.com/a/561609/102517
dreua

2

Đây là những gì tôi đã kết thúc bằng cách sử dụng:

file1=1stfile
file2=2ndfile
temp="$(mktemp -dp /mnt/sdcard)"
mv "$file1" $temp
mv "$file2" "$file1"
mv $temp/"$file1" "$file2"

Tôi sẽ thêm một số kiểm tra rằng các câu lệnh mv đã thành công, giống như các câu trả lời khác được đề xuất.
Walter A

@WalterA Dự án đó là EOL bây giờ. Tôi chỉ cần thêm câu trả lời cho lợi ích hoàn thành. Hãy chỉnh sửa.
Binoy Babu

1

Điều này mạnh mẽ hơn:

TMPFILE=tmp.$$
mv -- "$file1" $TMPFILE && mv -- "$file2" "$file1" && mv -- $TMPFILE "$file2"

trích dẫn là để ngăn chặn các vấn đề với khoảng trắng trong tên tệp, nó sử dụng tệp tmp và && làm cho lệnh sau chỉ chạy nếu kết thúc trước đó kết thúc thành công.


Cái này thế nào file1=1stfile && file2=2ndfile && temp="$(mktemp -dp /mnt/sdcard)" && mv "$file1" $temp && mv "$file2" "$file1" && mv $temp/"$file1" "$file2". Nó hoạt động. Cảm ơn vì đầu vào của bạn.
Binoy Babu


sử dụng mktemp là tốt; tìm thấy tốt đẹp
guido

nhưng chạy một lệnh với && trong java với runtime.exec () không hoạt động. :(
Binoy Babu

bạn phải trích dẫn biến yourShellInput của mình: String yourShellInput = "\" echo hi && echo ho \ ""; hoặc nếu ouy có dấu ngoặc kép trong lệnh của bạn String yourShellInput = "'echo hi && echo ho'";
guido
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.