主要的问题是生成输出的程序是在后台启动的,所以我读取的函数可以简洁地写入日志文件.这可能是一个问题吗?回声总是只写一条线,所以不应该很难保证原子性.然而,我已经在谷歌看,我没有找到没有办法确保它实际上是原子的.
以下是当前脚本:
LOG_FILE=/path/to/logfile write_log() { echo "$(date +%Y%m%d%H%M%S);$1" >> ${LOG_FILE} } write_output() { while read data; do write_log "Message from SUB process: [ $data ]" done } write_log "Script started" # do some stuff call_complicated_program 2>&1 | write_output & SUB_PID=$! #do some more stuff write_log "Script exiting" wait $SUB_PID@H_301_6@
Atomic/non-atomic: A write is atomic if the whole amount written in one operation is not interleaved with data from any other process. This is useful when there are multiple writers sending data to a single reader. Applications need to know how large a write request can be expected to be performed atomically.This maximum is called {PIPE_BUF}. Thisvolume of IEEE Std 1003.1-2001 does not say whether write requests for more than {PIPE_BUF} bytes are atomic,but requires that writes of {PIPE_BUF}or fewer bytes shall be atomic.
您可以使用简单的C程序来检查系统上的PIPE_BUF.如果你只是打印一行输出,这不是很长的,它应该是原子的.
这是一个简单的程序来检查PIPE_BUF的值:
#include <limits.h> #include <stdio.h> int main(void) { printf("%d\n",PIPE_BUF); return 0; }@H_301_6@在Mac OS X上,这给了我512(PIPE_BUF的minimum allowed value).在Linux上,我得到4096.所以如果你的行相当长,请确保你在有问题的系统上检查它.
编辑添加:我决定在Bash中检查the implementation of
echo
,以确认它将以原子方式打印.事实证明,echo使用putchar或printf取决于是否使用-e选项.这些是缓冲的stdio操作,这意味着它们会填满一个缓冲区,实际上只有当一个换行符(行缓冲模式)才能写入缓冲区,缓冲区被填充(以块缓冲的方式),或者你明确地刷新输出fflush.默认情况下,如果是交互式终端,流将处于行缓冲模式,如果是任何其他文件,则将阻塞缓冲模式. Bash从不设置缓冲类型,因此对于您的日志文件,它应该默认为阻止缓冲模式.然后end of theecho
builtin,Bash callsfflush
刷新输出流.因此,输出将始终在回波结束时被刷新,但如果不适合缓冲区,则可能会先刷新输出.使用的缓冲区的大小可能是BUFSIZ,尽管它可能不同;如果使用setbuf显式设置缓冲区,BUFSIZ是默认大小,但是没有可移植的方式来确定实际的缓冲区大小.对于什么BUFSIZ也没有便携式指南,但是当我在Mac OS X和Linux上测试时,它是PIPE_BUF的两倍.
这是什么意思?由于回声的输出全部被缓冲,所以在缓冲区被填充或调用fflush之前,它不会实际调用写操作.在这一点上,输出应该写成,上面提到的原子性保证应该适用.如果stdout缓冲区大小大于PIPE_BUF,则PIPE_BUF将是可以写出的最小原子单位.如果PIPE_BUF大于stdout缓冲区大小,那么当缓冲区填满时,流将写入缓冲区.
因此,只能保证回波原子写入比PIPE_BUF中较小的序列和最可能为BUFSIZ的stdout缓冲区的大小.在大多数系统上,BUFSIZ比PIPE_BUF大.
tl; dr:echo将原子输出行,只要这些行足够短.在现代系统中,您可能最多可以安装512个字节,但是无法可靠地确定限制.