Mặc dù đây là một câu hỏi cũ, nhưng đối với tôi, đây dường như là một câu hỏi lâu năm và một giải pháp rõ ràng, tổng quát hơn có sẵn hơn so với đề xuất cho đến nay. Tín dụng khi tín dụng đáo hạn: Tôi không chắc chắn tôi sẽ đến với nó mà không xem xét đề cập của Stéphane Chazelas về <>
nhà điều hành cập nhật.
Mở một tệp để cập nhật trong trình bao Bourne là tiện ích hạn chế. Shell cung cấp cho bạn không có cách nào để tìm kiếm trên một tệp và không có cách nào để đặt độ dài mới của nó (nếu ngắn hơn tệp cũ). Nhưng điều đó dễ dàng được khắc phục, vì vậy tôi rất ngạc nhiên khi nó không nằm trong số các tiện ích tiêu chuẩn /usr/bin
.
Những công việc này:
$ grep -n foo T
8:foo
$ (exec 4<>T; grep foo T >&4 && ftruncate 4) && nl T;
1 foo
Cũng như điều này (mũ cho Stéphane):
$ { grep foo T && ftruncate; } 1<>T && nl T;
1 foo
(Tôi đang sử dụng GNU grep. Có lẽ có gì đó đã thay đổi kể từ khi anh ấy viết câu trả lời của mình.)
Ngoại trừ, bạn không có / usr / bin / ftruncate . Đối với một vài chục dòng C, bạn có thể, xem bên dưới. Tiện ích ftruncate này cắt một bộ mô tả tệp tùy ý thành một độ dài tùy ý, mặc định là đầu ra tiêu chuẩn và vị trí hiện tại.
Lệnh trên (ví dụ 1)
- mở mô tả tập tin 4 trên
T
để cập nhật. Cũng giống như mở (2), mở tệp theo cách này đặt vị trí bù hiện tại là 0.
- grep sau đó xử lý
T
bình thường và shell chuyển hướng đầu ra của nó T
thông qua bộ mô tả 4.
- ftruncate gọi ftruncate (2) trên bộ mô tả 4, đặt độ dài thành giá trị của phần bù hiện tại (chính xác là nơi grep rời nó).
Subshell sau đó thoát, đóng mô tả 4. Đây là ftruncate :
#include <err.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
int
main( int argc, char *argv[] ) {
off_t i, fd=1, len=0;
off_t *addrs[2] = { &fd, &len };
for( i=0; i < argc-1; i++ ) {
if( sscanf(argv[i+1], "%lu", addrs[i]) < 1 ) {
err(EXIT_FAILURE, "could not parse %s as number", argv[i+1]);
}
}
if( argc < 3 && (len = lseek(fd, 0, SEEK_CUR)) == -1 ) {
err(EXIT_FAILURE, "could not ftell fd %d as number", (int)fd);
}
if( 0 != ftruncate((int)fd, len) ) {
err(EXIT_FAILURE, argc > 1? argv[1] : "stdout");
}
return EXIT_SUCCESS;
}
NB, ftruncate (2) là không thể truy cập khi được sử dụng theo cách này. Để có tính tổng quát tuyệt đối, hãy đọc byte được viết cuối cùng, mở lại tệp O_WRONLY, tìm kiếm, viết byte và đóng.
Cho rằng câu hỏi là 5 tuổi, tôi sẽ nói rằng giải pháp này là không gây khó chịu. Nó tận dụng lợi thế của exec để mở một mô tả mới và <>
toán tử, cả hai đều là phức tạp. Tôi không thể nghĩ ra một tiện ích tiêu chuẩn thao tác inode bằng mô tả tập tin. (Cú pháp có thể là ftruncate >&4
, nhưng tôi không chắc rằng đó là một cải tiến.) Nó ngắn hơn đáng kể so với câu trả lời thăm dò, có thẩm quyền của camh. Nó chỉ rõ ràng hơn một chút so với Stéphane, IMO, trừ khi bạn thích Perl hơn tôi. Tôi hy vọng ai đó thấy nó hữu ích.
Một cách khác để làm điều tương tự sẽ là một phiên bản thực thi của lseek (2) báo cáo phần bù hiện tại; đầu ra có thể được sử dụng cho / usr / bin / truncate , mà một số Linuxi cung cấp.