Làm thế nào là sửa đổi tại chỗ của một tập tin đang được thực hiện?


10

Việc sửa đổi "tại chỗ" của một tập tin, ví dụ như thông qua sed -ihoặc perl -icó nghĩa là gì?
Câu hỏi của tôi là về cách sửa đổi tại chỗ này được thực hiện. Là tập tin sao chép sửa đổi được thực hiện trong bản sao và sau đó thay thế bản gốc? Hoặc là tập tin gốc bằng cách nào đó được sửa đổi tại chỗ?


Hãy xem backreference.org/2011/01/29/in-place-editing-of-files để được giải thích chi tiết về chủ đề này.
14

Đối với vấn đề đó, làm thế nào nó được thực hiện với exhoặc vi?
tự đại diện

@Wildcard - mỗi người trong số họ có cả một hệ thống. exduy trì một mailfile (như, dead.mailhoặc một cái gì đó trong ~ bạn, và một cái khác ở đâu đó gần bộ đệm thư của bạn, thường) . kiểm tra thông số kỹ thuật - mỗi trong số chúng có trạng thái được xác định rất dài ... excó định dạng nhị phân riêng trong hầu hết các trường hợp (xem -rescuetệp của bạn ) và điều này được sử dụng để prezero tách các tệp bộ đệm tạm thời (có thể lên đến sáu) . Vì vậy, những bản sao này ra khỏi khối đầu vào để chỉnh sửa bộ đệm đồng bộ ghi vào phần bù cho mỗi thay đổi :!written?
mikeerv

Câu trả lời:


18

sed tạo một tệp tạm thời, ghi đầu ra vào tệp đó và sau đó đổi tên tệp tạm thời trên đầu của bản gốc.

Bạn có thể xem những gì xảy ra bằng cách sử dụng strace:

$ strace -e trace=file sed -i -e '' a
execve("/usr/bin/sed", ["sed", "-i", "-e", "", "a"], [/* 34 vars */]) = 0
<...trimmed...>
open("a", O_RDONLY)                     = 3
open("./sedxvhRY8", O_RDWR|O_CREAT|O_EXCL, 0600) = 4
rename("./sedxvhRY8", "a")              = 0
+++ exited with 0 +++

Thao tác này ghi lại tất cả các thao tác tệp sedtạo ra: nó tạo một tệp mới (an toàn với O_CREAT|O_EXCL), ghi dữ liệu vào đó và sau đó di chuyển nó trở lại trên đầu tệp gốc của tôi a.

sed -ichấp nhận một hậu tố để sử dụng cho một bản sao lưu, và trong trường hợp đó, nó di chuyển bản gốc ra khỏi đầu tiên (thay vì đổi tên trên đầu trang). Đối số đó là bắt buộc trong hầu hết các BSD sed. Trong trường hợp này, có một thời gian ngắn khi không có tệp nào đúng tên trong thư mục cả.

perl trong các phiên bản gần đây sẽ mở tệp đầu vào, sau đó xóa tệp đó và tạo một tệp mới có cùng tên:

open("a", O_RDONLY)               = 3
unlink("a")                       = 0
open("a", O_WRONLY|O_CREAT|O_EXCL, 0600) = 4

Khi bạn xóa ( unlink) một tệp bạn đã mở, bạn sẽ giữ quyền truy cập vào nó miễn là bạn giữ tay cầm xung quanh, để nó có thể tiếp tục đọc dữ liệu ra khỏi tệp đã bị xóa. Theo cách này, perlghi trực tiếp vào tệp đầu ra, thay vì vào tệp tạm thời: không có tệp bổ sung nào được tạo, nhưng nếu bạn đọc tệp trong quá trình, bạn sẽ nhận được một phần nội dung, không giống như sedcách tiếp cận. Cũng có một thời gian ngắn khi không có tệp nào có tên đúng, đó là lúc bắt đầu quá trình chứ không phải là kết thúc (như trong sed -i .bak).


Cả hai sedperlsẽ:

  • Thay thế một liên kết tượng trưng bằng một tập tin thông thường.
  • Phá vỡ liên kết cứng.
  • Bảo toàn quyền sở hữu nhóm nếu có thể.
  • Tạo tệp với nhóm mặc định của bạn (hoặc nhóm của thư mục mẹ nếu thư mục đó có setgidbit) nếu nó thuộc sở hữu của một nhóm bạn không thuộc và bạn không root.
  • Giữ quyền sở hữu tập tin nếu bạn root.
  • Bảo toàn quyền cơ bản.
  • Bảo toàn setuidsetgrpbit, nếu nhóm kết quả giống với nhóm mà nó bắt đầu.
  • Bảo quản bit dính.
  • Không bảo quản xattrs.

sed sẽ:

  • Bảo tồn ACL (Trên Linux; tôi không biết về người khác) .

perl sẽ:

  • Không bảo quản ACL.

Điều trên đúng với Linux với GNU sedvà Mac OS X với (có nguồn gốc FreeBSD) sed.


3

Ngoài câu trả lời của @ Homer, từ perldoc perlrun:

chỉ định rằng các tệp được xử lý bởi cấu trúc "<>" sẽ được chỉnh sửa tại chỗ. Nó thực hiện điều này bằng cách đổi tên tệp đầu vào, mở tệp đầu ra theo tên gốc và chọn tệp đầu ra đó làm mặc định cho các câu lệnh print (). Phần mở rộng, nếu được cung cấp, được sử dụng để sửa đổi tên của tệp cũ để tạo bản sao lưu, tuân theo các quy tắc sau:

Nếu không có phần mở rộng nào được cung cấp, không có bản sao lưu nào được tạo và tệp hiện tại bị ghi đè.

Nếu tiện ích mở rộng không chứa dấu *, thì nó được gắn vào cuối tên tệp hiện tại dưới dạng hậu tố. Nếu tiện ích mở rộng có chứa một hoặc nhiều ký tự *, thì mỗi * được thay thế bằng tên tệp hiện tại.

Và hãy nhớ rằng, không có liên kết mềm hoặc liên kết cứng nào được bảo tồn:

Lưu ý rằng vì -i đổi tên hoặc xóa tệp gốc trước khi tạo một tệp mới cùng tên, các liên kết mềm và cứng kiểu UNIX sẽ không được giữ nguyên.

Cuối cùng, công tắc -i không cản trở việc thực thi khi không có tệp nào được đưa ra trên dòng lệnh. Trong trường hợp này, không có bản sao lưu nào được tạo ra (dĩ nhiên, tệp gốc không thể được xác định) và xử lý tiền thu được từ STDIN đến STDOUT như mong đợi.

Điều này cũng giải thích lý do tại sao bạn phải sử dụng -ivới -ptùy chọn hoặc sử dụng printcâu lệnh rõ ràng nếu bạn muốn chỉnh sửa tại chỗ với perl:

# Opps, file will be truncated, becomes empty
$ perl -i.bak -ne 's/123/qwe/' file

# Right way
$ perl -i.bak -ne 's/123/qwe/;print' file

# Or
$ perl -i.bak -pe 's/123/qwe/' file
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.