Linux non-blocking fifo (on demand logging)

前端 未结 10 2312
你的背包
你的背包 2020-11-29 19:20

I like to log a programs output \'on demand\'. Eg. the output is logged to the terminal, but another process can hook on the current output at any time.

The classic

10条回答
  •  庸人自扰
    2020-11-29 19:51

    The problem with the given fifo approach is that the whole thing will hang when the pipe buffer is getting filled up and no reading process is taking place.

    For the fifo approach to work I think you would have to implement a named pipe client-server model similar to the one mentioned in BASH: Best architecture for reading from two input streams (see slightly modified code below, sample code 2).

    For a workaround you could also use a while ... read construct instead of teeing stdout to a named pipe by implementing a counting mechanism inside the while ... read loop that will overwrite the log file periodically by a specified number of lines. This would prevent an ever growing log file (sample code 1).

    # sample code 1
    
    # terminal window 1
    rm -f /tmp/mylog
    touch /tmp/mylog
    while sleep 2; do date '+%Y-%m-%d_%H.%M.%S'; done 2>&1 | while IFS="" read -r line; do 
      lno=$((lno+1))
      #echo $lno
      array[${lno}]="${line}"
      if [[ $lno -eq 10 ]]; then
        lno=$((lno+1))
        array[${lno}]="-------------"
        printf '%s\n' "${array[@]}" > /tmp/mylog
        unset lno array
      fi
      printf '%s\n' "${line}"
    done
    
    # terminal window 2
    tail -f /tmp/mylog
    
    
    #------------------------
    
    
    # sample code 2
    
    # code taken from: 
    # https://stackoverflow.com/questions/6702474/bash-best-architecture-for-reading-from-two-input-streams
    # terminal window 1
    
    # server
    (
    rm -f /tmp/to /tmp/from
    mkfifo /tmp/to /tmp/from
    while true; do 
      while IFS="" read -r -d $'\n' line; do 
        printf '%s\n' "${line}"
      done /tmp/from &
      bgpid=$!
      exec 3>/tmp/to
      exec 4/tmp/to;
    exec 4 /dev/null
      else       
        printf 'line from fifo: %s\n' "$line"       > /dev/null
      fi
    done &
    trap "kill -TERM $"'!; exit' 1 2 3 13 15
    while IFS="" read -r -d $'\n' line; do
      # can we make it atomic?
      # sleep 0.5
      # dd if=/tmp/to iflag=nonblock of=/dev/null  # flush fifo
      printf '\177%s\n' "${line}"
    done >&3
    ) &
    # kill -TERM $!
    
    
    # terminal window 2
    # tests
    echo hello > /tmp/to
    yes 1 | nl > /tmp/to
    yes 1 | nl | tee /tmp/to
    while sleep 2; do date '+%Y-%m-%d_%H.%M.%S'; done 2>&1 | tee -a /tmp/to
    
    
    # terminal window 3
    cat /tmp/to | head -n 10
    

提交回复
热议问题