amoffat / sh

Python process launching

Home Page:https://sh.readthedocs.io/en/latest/

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

trouble with `_out` vs _fg`

redthing1 opened this issue · comments

Hello,

So I have been working with ab-av1 which is a video encoder that draws a progress bar (in the standard form of writing to stderr with \r)

So _fg is great for synchronously running the command and also keeping the progress bar.
And when I need to pass some more options, _out=sys.stdout, _err=sys.stderr works too, and preserves the progress bar.

But when I want to capture outputs AND run synchronously, I cannot find a way to do this.
There's _tee referenced here which lets me both pipe stderr AND capture it to a variable, but I cannot find a way to make this work that preserves the progress bars.

I'm running ab-av1 crf-search -i somevideo.mp4

Any idea how I could do all of the following at once:

  1. capture outputs
  2. run synchronously
  3. keep progress bars working
commented

You probably want to look into _tty_in and _tty_out. Many programs change their behavior based on whether or not they think they're connected to a tty. I suspect fiddling with those will get you the progress bar back.

First of all, this is one of my favorite libraries and I appreciate the rapid response.

I'm doing my best to run the command in the foreground but also capture stderr.

running_encode_cmd = encode_cmd(_err=sys.stderr)

This does run it in the foreground and shows progress bars, but it returns an empty stdout and stderr to the sh.ErrorReturnCode

I want this foreground execution and capturing the output.

I found _tee for this:

running_encode_cmd = encode_cmd(_tee="err")

This does return the output but doesn't print it live to the foreground.

Any hints on this?

commented

Sorry, I misunderstood.

Try encode_cmd(_out=sys.stdout, _err_to_out=True, _tee="out")

  • _out=sys.stdout sends the output to your terminal
  • _err_to_out=True sends the stderr to the same place that stdout is going
  • _tee="out" sends stdout (which also contains stderr, thanks to _err_to_out) to be returned as well as sent to the stdout handler (in this case sys.stdout)

That should print stderr + stdout to the terminal, while also returning it.

commented

Alternatively there is a way to do this with iteration, iterating line by line over the command that you're running, allowing you to save the output and print it if you want to. A long-running encoding command seems more suited towards this. Check out _iter if you're interested. You'll also need to use _err_to_out to get at the stderr as well though.

Thank you!

This appears to work:

            for line in encode_cmd(_iter=True, _err_to_out=True, _out_bufsize=0):
                # write it to stdout
                if isinstance(line, bytes):
                    sys.stdout.buffer.write(line)
                else:
                    sys.stdout.write(line)