Perl Deniel
Perl Deniel

Reputation: 43

How to generate a string output with subprocess in Python3

I have a script that saves 5 seconds length of videos locally and it omits the file name.

Here's the bash command

ffmpeg -i http://0.0.0.0:8080/stream/video.mjpeg -vcodec copy -map 0 -f segment -segment_time 2 -loglevel 40 -segment_format mp4 capture-%05d.mp4 2>&1 | grep --line-buffered -Eo "segment:.+ended" | gawk -F "'" '{print $2; system("")}' | xargs -n1 

If I run this command in the terminal, it will return the expected file name, as such

capture-00001.mp4

Notice that the xargs command at the end easily lets me to pass the file name to a python script as a new argument. But now I want to execute this command within Python itself, specifically getting the file name with subprocess.

Here's what I've done so far. When running the script, as expected the terminal will print the file name, but it never pass it as a string to fName. I've tried subprocess.check_output but it never passes anything as the command continuously capture videos and save it locally.

FFMPEG_SCRIPT = r"""ffmpeg -i http://0.0.0.0:8080/stream/video.mjpeg -vcodec copy -map 0 -f segment -segment_time 2 -loglevel 40 -segment_format mp4 capture-%05d.mp4 2>&1 | grep --line-buffered -Eo "segment:.+ended" | gawk -F "'" '{print $2; system("")}' | xargs -n1 """

try:
    fName = subprocess.check_call(FFMPEG_SCRIPT, stderr=subprocess.STDOUT, shell=True).decode('utf-8')
    print(">>> {}".format(fName))
except subprocess.CalledProcessError as e:
    print(e.output)

Upvotes: 2

Views: 244

Answers (3)

lalebarde
lalebarde

Reputation: 1816

Here is a version based on Alexandre Cox proposal with a piped command to check a mount:

import subprocess

fName = subprocess.Popen('mount | grep sda3 | cut -d " " -f 3', shell=True, stdin=subprocess.PIPE, stdout=subprocess.PIPE)
(stdout, stderr) = fName.communicate()
print(">>> {}".format(fName))
print(stdout)

If the mount exists, the output is:

>>> <subprocess.Popen object at 0x7f9b5eb2fdd8>
b'/mnt/sda3\n'

Upvotes: 0

Serge Ballesta
Serge Ballesta

Reputation: 149175

That is a common problem when you pipe commands. The IO subsystem processes differently output on terminal and on files or pipes. On terminal, output is flushed on each newline, which does not append on files or pipes unless the program specifically asks for an explicit flush.

It is not a problem on pipelines where the first command ends on an end of file, because everything is flushed before the command exists, and the write end of the pipe is closed. So next commands sees an end of file and everything propagates smoothly.

But when the first program contains an infinite reading loop, it does queue its output, but nothing is flushed until the buffer is full, and buffers are huge on modern systems. In that case, everything works fine but you cannot see any output.

Upvotes: 0

Alexandre Cox
Alexandre Cox

Reputation: 528

import subprocess
from subprocess import PIPE

fName = subprocess.Popen("test.bat", stdin=PIPE, stdout=PIPE)
(stdout, stderr) = fName.communicate()
print(">>> {}".format(fName))
print(stdout)

test.bat is a simple echo yes since I can't test with your script, and the resulting output of print(stdout) is b'yes\r\n'. If the file name is the only thing the scripts prints, it shouldn't be too hard to extract it.

Upvotes: 1

Related Questions