echo
chỉ là một trình bao bọc đơn giản xung quanh write
(đây là cách đơn giản; xem phần chỉnh sửa bên dưới để biết chi tiết đẫm máu), vì vậy để xác định xem tiếng vọng có phải là nguyên tử hay không. Từ single UNIX specification:
Atomic/phi nguyên tử: A ghi là nguyên tử nếu toàn bộ số tiền viết bằng một hoạt động không được xen kẽ với các dữ liệu từ bất kỳ quá trình khác. Điều này rất hữu ích khi có nhiều nhà văn gửi dữ liệu đến một người đọc duy nhất. Các ứng dụng cần phải biết yêu cầu viết lớn đến mức nào có thể được mong đợi thực hiện nguyên tử. Tối đa này được gọi là {PIPE_BUF}. Thisvolume của IEEE Std 1003.1-2001 không nói liệu các yêu cầu viết có nhiều hơn {PIPE_BUF} byte là nguyên tử hay không, nhưng yêu cầu viết {PIPE_BUF} hoặc ít byte hơn sẽ là nguyên tử.
Bạn có thể kiểm tra PIPE_BUF
trên hệ thống của mình bằng chương trình C đơn giản. Nếu bạn chỉ in một dòng đầu ra, đó không phải là quá dài, nó phải là nguyên tử.
Đây là một chương trình đơn giản để kiểm tra giá trị của PIPE_BUF
:
#include <limits.h>
#include <stdio.h>
int main(void) {
printf("%d\n", PIPE_BUF);
return 0;
}
Trên Mac OS X, mà mang lại cho tôi 512 (các minimum allowed value cho PIPE_BUF
). Trên Linux, tôi nhận được 4096. Vì vậy, nếu các dòng của bạn là khá dài, hãy chắc chắn rằng bạn kiểm tra nó trên hệ thống trong câu hỏi.
chỉnh sửa để thêm: Tôi quyết định kiểm tra the implementation of echo
trong Bash, để xác nhận rằng nó sẽ in nguyên tử. Hóa ra, echo
sử dụng putchar
hoặc printf
tùy thuộc vào việc bạn có sử dụng tùy chọn -e
hay không. Đây là các hoạt động stdio đệm, có nghĩa là chúng điền vào một bộ đệm, và thực sự viết nó ra chỉ khi một dòng mới đạt được (trong chế độ dòng đệm), bộ đệm được điền (trong chế độ khối đệm), hoặc bạn rõ ràng tuôn ra đầu ra với fflush
. Theo mặc định, một luồng sẽ ở chế độ đệm theo dòng nếu đó là một thiết bị đầu cuối tương tác và chặn chế độ đệm nếu đó là bất kỳ tệp nào khác. Bash không bao giờ đặt kiểu đệm, vì vậy đối với tệp nhật ký của bạn, nó nên mặc định để chặn chế độ đệm. Lúc đó end of the echo
builtin, Bash calls fflush
để xóa luồng đầu ra. Vì vậy, đầu ra sẽ luôn luôn được xả vào cuối echo
, nhưng có thể được xả trước đó nếu nó không phù hợp với bộ đệm.
Kích thước của bộ đệm được sử dụng có thể là BUFSIZ
, mặc dù nó có thể khác; BUFSIZ
là kích thước mặc định nếu bạn đặt bộ đệm một cách rõ ràng bằng cách sử dụng setbuf
, nhưng không có cách nào để xác định kích thước thực tế của bộ đệm của bạn. Cũng không có hướng dẫn di động cho những gì BUFSIZ
là, nhưng khi tôi thử nghiệm nó trên Mac OS X và Linux, nó là hai lần kích thước của PIPE_BUF
.
Điều này có nghĩa là gì? Vì đầu ra của echo
là tất cả bộ đệm, nó sẽ không thực sự gọi write
cho đến khi bộ đệm được lấp đầy hoặc fflush
được gọi. Tại thời điểm đó, đầu ra phải được viết và đảm bảo nguyên tử tôi đã đề cập ở trên sẽ áp dụng. Nếu kích thước bộ đệm tiêu chuẩn lớn hơn PIPE_BUF
thì PIPE_BUF
sẽ là đơn vị nguyên tử nhỏ nhất có thể được viết ra. Nếu PIPE_BUF
lớn hơn kích thước bộ đệm chuẩn, thì luồng sẽ ghi bộ đệm ra khi bộ đệm lấp đầy.
Vì vậy, echo
chỉ được đảm bảo ghi nguyên tử chuỗi ngắn hơn nhỏ hơn PIPE_BUF
và kích thước của bộ đệm đồ chuẩn, rất có thể là BUFSIZ
. Trên hầu hết các hệ thống, BUFSIZ
lớn hơn PIPE_BUF
.
tl; dr: echo
sẽ xuất dòng nguyên tử, miễn là các dòng đó đủ ngắn. Trên các hệ thống hiện đại, bạn có thể an toàn lên đến 512 byte, nhưng không thể xác định giới hạn một cách hợp lý.
Tôi không nghĩ rằng bash là công cụ thích hợp cho công việc này. Tôi muốn đề nghị một cái gì đó mạnh hơn (perl, python, ruby ..) – Daenyth
Ngẫu nhiên, nếu bạn có * nhiều * dữ liệu đi vào nhật ký này thì bạn có thể thấy rằng việc mở và đóng liên tục tệp nhật ký là một ý tưởng tồi. Bạn có thể mở vĩnh viễn một tập tin với 'exec 3 >> $ {LOG_FILE}' và sau đó ghi vào nó bất cứ lúc nào bạn thích với 'echo anything> & 3'. Bạn có thể đóng tệp bằng 'exec 3> & -', nhưng điều đó sẽ xảy ra khi tập lệnh thoát. Vấn đề duy nhất là bạn phải tự chọn một số cho mỗi tệp bạn mở và 0, 1 và 2 đã được sử dụng. – ams