Cảnh báo về '>'
Những người mới bắt đầu Unix mới tìm hiểu về chuyển hướng I / O ( <
và >
) thường thử những thứ như
lệnh ... input_file > the_same_file
hoặc là
chỉ huy < file > the_same_file
hoặc, gần như tương đương,
tập tin mèo | chỉ huy > the_same_file
( grep
, sed
, cut
, sort
, Và spell
là ví dụ về các lệnh mà mọi người đang bị cám dỗ để sử dụng trong các cấu trúc như thế này.) Người dùng có ngạc nhiên khi khám phá ra rằng những tình huống dẫn đến tập tin trở nên trống rỗng.
Một sắc thái dường như không được đề cập trong câu trả lời khác có thể được tìm thấy ẩn trong câu đầu tiên của phần Chuyển hướng của bash (1) :
Trước khi một lệnh được thực thi, đầu vào và đầu ra của nó có thể được chuyển hướng
bằng cách sử dụng một ký hiệu đặc biệt được giải thích bởi shell.
Năm từ đầu tiên phải được in đậm, in nghiêng, gạch chân, phóng to, nhấp nháy, tô màu đỏ và được đánh dấu bằng một biểu tượng, để nhấn mạnh thực tế là trình bao thực hiện (các) chuyển hướng được yêu cầu
trước khi lệnh được thực thi . Và cũng nhớ
Chuyển hướng đầu ra làm cho tập tin được mở ra để viết tập tin. Nếu tập tin không tồn tại, nó được tạo ra; nếu nó tồn tại, nó bị cắt cụt về kích thước không.
Vì vậy, trong ví dụ này:
sort roster > roster
Shell mở roster
tệp để ghi, cắt bớt nó (nghĩa là loại bỏ tất cả nội dung của nó), trước khi sort
chương trình bắt đầu chạy. Đương nhiên, không có gì có thể được thực hiện để phục hồi dữ liệu.
Người ta có thể ngây thơ mong đợi rằng
tr "[:upper:]" "[:lower:]" < poem > poem
có thể tốt hơn Vì shell xử lý các chuyển hướng từ trái sang phải, nó sẽ mở ra poem
để đọc (đối với tr
đầu vào tiêu chuẩn) trước khi mở nó để ghi (cho đầu ra tiêu chuẩn). Nhưng nó không giúp được gì. Mặc dù chuỗi thao tác này mang lại hai xử lý tệp, cả hai đều trỏ đến cùng một tệp. Khi shell mở tệp để đọc, nội dung vẫn ở đó, nhưng chúng vẫn bị ghi đè trước khi chương trình được thực thi.
Vậy giờ làm gì với nó?
Các giải pháp bao gồm:
Kiểm tra xem chương trình bạn đang chạy có khả năng, nội bộ, riêng để xác định nơi đầu ra đi không. Điều này thường được chỉ định bởi một -o
(hoặc --output=
) mã thông báo. Đặc biệt,
sort roster -o roster
gần tương đương với
sort roster > roster
ngoại trừ, trong trường hợp đầu tiên, sort
chương trình mở tệp đầu ra. Và nó đủ thông minh để không mở tệp đầu ra cho đến khi nó đã đọc tất cả (các) tệp đầu vào.
Tương tự như vậy, ít nhất là một số phiên bản của sed
có một -i
(chỉnh sửa i n đặt) tùy chọn có thể được sử dụng để viết các đầu ra trở ra đến tập tin đầu vào (một lần nữa, sau khi tất cả các đầu vào đã được đọc). Biên tập như ed
/ ex
, emacs
, pico
, và vi
/ vim
cho phép người dùng chỉnh sửa một tập tin văn bản và lưu văn bản chỉnh sửa trong file gốc. Lưu ý rằng ed
(ít nhất) có thể được sử dụng không tương tác.
vi
có một tính năng liên quan. Nếu bạn gõ , nó sẽ ghi nội dung của bộ đệm chỉnh sửa ra , đọc đầu ra và chèn nó vào bộ đệm (thay thế nội dung ban đầu).:%!command
Entercommand
Đơn giản mà hiệu quả:
lệnh ... input_file > temp_file && mv temp_file input_file
Điều này có nhược điểm là, nếu input_file
là một liên kết, nó (có thể) sẽ được thay thế bằng một tệp riêng. Ngoài ra, tập tin mới sẽ thuộc sở hữu của bạn, với sự bảo vệ mặc định. Đặc biệt, điều này mang đến rủi ro rằng tập tin sẽ trở nên dễ đọc trên thế giới, ngay cả khi bản gốc input_file
không có.
Biến thể:
command … input_file > temp_file && cp temp_file input_file && rm temp_file
mà vẫn sẽ (có khả năng) rời khỏi temp_file
thế giới có thể đọc được. Thậm chí còn tốt hơn:
cp input_file temp_file && command … temp_file > input_file && rm temp_file
Chúng bảo vệ trạng thái liên kết, chủ sở hữu và chế độ (bảo vệ) của tệp, có khả năng với chi phí gấp đôi I / O. (Bạn có thể cần sử dụng một tùy chọn như -a
hoặc -p
bật cp
để nói với nó để bảo toàn các thuộc tính.)
command … input_file > temp_file &&
cp --attributes-only --preserve=all input_file temp_file &&
mv temp_file input_file
(được chia thành các dòng riêng biệt để dễ đọc) Điều này duy trì chế độ của tệp (và, nếu bạn là chủ sở hữu), nhưng làm cho nó thuộc sở hữu của bạn (nếu bạn không root) và làm cho nó mới, tập tin riêng biệt.
Blog này
(Chỉnh sửa các tập tin tại chỗ của EDT) gợi ý và giải thích
{rm input_file && ra lệnh > input_file ; } < input_file
Điều này đòi hỏi phải command
có khả năng xử lý đầu vào tiêu chuẩn (nhưng hầu như tất cả các bộ lọc đều có thể). Bản thân blog gọi đây là một loại bùn nguy hiểm và không khuyến khích sử dụng nó. Và điều này cũng sẽ tạo một tệp mới, riêng biệt (không được liên kết với bất cứ thứ gì), thuộc sở hữu của bạn và với các quyền mặc định.
Gói moreutils có một lệnh gọi là sponge
:
lệnh ... input_file | bọt biển the_same_file
Xem câu trả lời này để biết thêm thông tin.
Đây là một cái gì đó làm tôi ngạc nhiên hoàn toàn:
cú pháp nói :
[Hầu hết các giải pháp này] sẽ thất bại trên hệ thống tệp chỉ đọc, trong đó, chỉ đọc có nghĩa là có nghĩa là bạn $HOME
sẽ có thể ghi được, nhưng /tmp
sẽ chỉ đọc (theo mặc định). Chẳng hạn, nếu bạn có Ubuntu và bạn đã khởi động vào Recovery Console, đây thường là trường hợp. Ngoài ra, toán tử tài liệu ở đây <<<
cũng sẽ không hoạt động ở đó, vì nó yêu cầu /tmp
phải đọc / ghi
vì nó cũng sẽ ghi một tệp tạm thời vào đó.
(xem câu hỏi này bao gồm strace
đầu ra 'd)
Sau đây có thể làm việc trong trường hợp đó:
Vì vậy, câu hỏi là gì?
Đây là một chủ đề phổ biến trên U & L; nó được giải quyết trong các câu hỏi sau:
Nhiều thứ và không tính Super User hay hỏi Ubuntu. Tôi đã kết hợp rất nhiều thông tin từ câu trả lời cho các câu hỏi trên ở đây trong câu trả lời này, nhưng không phải tất cả. (Tức là, để biết thêm thông tin, hãy đọc các câu hỏi được liệt kê ở trên và câu trả lời của họ.)
PS Tôi không có liên kết với blog mà tôi đã trích dẫn, ở trên.