Bash process substitution in Python with Popen

Question:

I’m attempting to create a looped video file by calling ffmpeg from the python subprocess library. Here’s the part that’s giving me problems:

import subprocess as sp
sp.Popen(['ffmpeg', '-f', 'concat', '-i', "<(for f in ~/Desktop/*.mp4; do echo "file '$f'"; done)", "-c", "copy", "~/Desktop/sample3.mp4"])

With the above code I’m getting the following error:

<(for f in /home/delta/Desktop/*.mp4; do echo "file '$f'"; done): No such file or directory

I did find a similarly phrased question here. But I’m not sure how the solution might apply to solving my issue.

Asked By: moorej

||

Answers:

Following the advice in the comments and looking elsewhere I ended up changing the code to this:

sp.Popen("ffmpeg -f concat -i <(for f in ~/Desktop/*.mp4; do echo "file '$f'"; done) -c copy ~/Desktop/sample3.mp4",
         shell=True, executable="/bin/bash")

–which works fine. – moorej


If you need to parameterize input and output files, consider breaking out your parameters:

# sample variables
inputDirectory = os.path.expanduser('~/Desktop')
outputDirectory = os.path.expanduser('~/dest.mp4')

sp.Popen(['''ffmpef -f concat -i <(for f in "$1"/*; do
                                     echo "file '$f'";
                                   done) -c copy "$2" ''',
          bash,            # this becomes $0
          inputDirectory,  # this becomes $1
          outputDirectory, # this becomes $2
         ], shell=True, executable="/bin/bash") 

…as this ensures that your code won’t do untoward things even when given an input directory with a hostile name like /uploads/$(rm -rf ~)'$(rm -rf ~)'. (ffmpeg is likely to fail to parse an input file with such a name, and if there’s any video you don’t want included in the current working directory but we’d need to know the escaping rules it uses to avoid that; but it’s far better for ffmpeg to fail than to execute arbitrary code).

Answered By: Armali
Categories: questions Tags: , ,
Answers are sorted by their score. The answer accepted by the question owner as the best is marked with
at the top-right corner.