bash I/O redirection - how to append to stderr

I have a script that loops over some big collection of data and performs some lenghty operations. Then i need to sort | uniq -c its output. So to let it know that its alive, I print a dot every N items on stderr (very primitive pseudo progress-bar), so it looks pretty much like this:

for i in {1..100}; do 
    [[ $(( (i+=1) % 10)) -eq 0 ]] && echo -n "." >&2
    shuf -i 1-10 -n1
    sleep 0.1
done | sort | uniq -c 

and the output:

..........      9 1
     10 10
      8 2
     14 3
     13 4
      9 5
     11 6
      8 7
      8 8
     10 9

the "progress bar" messes up the output a little - so i was wondering:

  • is there an easy way to add a nweline to that stderr before flushing that stdout? (probably echo >&2 is all I need)
  • or remove it ?

of course in reeality i dont know wow many items there are (at least not out-of-the box). So i was wondering if this can be acieved by some stream redirection

Answers 1

  • Wrap the loop in braces (or parentheses) and put the extra echo inside them:

    { for i in {1..100}; do 
        [[ $(( (i+=1) % 10)) -eq 0 ]] && echo -n "." >&2
        shuf -i 1-10 -n1
        sleep 0.1
    done; echo >&2; } | sort | uniq -c 
    

    With the whole brace group redirected to sort, it has to wait for everything inside to exit before seeing an end-of-file so it can proceed. That ensures the newline is printed before any of the output from sort and uniq.


Related Questions