smartzer
smartzer

Reputation: 89

Using wildcards in subprocess.Popen

I have found a couple answers that solve the problem of passing wildcards through Popen, but I can't seem to get those solutions to work for my particular case.

I have a project that will merge an audio and video file when a button is pressed, and I need to use subprocess.Popen to execute the command I want:

mergeFile = "ffmpeg -i /home/pi/Video/* -i /home/pi/Audio/test.wav -acodec copy -vcodec copymap 0:v -map 1:a /home/pi/Test/output.mkv"
proc= subprocess.Popen(shlex.split(mergeFiles), shell=True)

I basically want to take whatever file is in my Video folder (my project downloads videos from a camera and the name of the file changes every time a new video is saved) and merge the audio from a separate "Audio" folder and then save that file to yet another folder.

I have tried setting the shell to true, and nothing works.

I also don't know how the glob module would help me in this scenario.

Upvotes: 0

Views: 1348

Answers (1)

Charles Duffy
Charles Duffy

Reputation: 295687

The problem here is the shlex.split(). When used in conjunction with shell=True, it means that only the string ffmpeg is treated as a script, and that the other components of your command line are passed as arguments to that script (which it never looks at / reads).

mergeFile = "ffmpeg -i /home/pi/Video/* -i /home/pi/Audio/test.wav -acodec copy -vcodec copymap 0:v -map 1:a /home/pi/Test/output.mkv"
proc = subprocess.Popen(mergeFile, shell=True)

A better-practice alternative that still uses shell=True (if you're actually parameterizing the directory names and filenames) might be:

mergeFile=[
    'ffmpeg -i "$1"/* -i "$2" -acodec copy -vcodec copymap 0:v -map 1:a "$3"',
    '_',                          # placeholder for $0
    "/home/pi/Video",             # directory for $1 -- can use a variable here
    "/home/pi/Audio/test.wav",
    "/home/pi/Test/output.mkv",
]
subprocess.Popen(mergeFile, shell=True)

...in which case the script itself is constant (and can't have its meaning changed by values injected via filenames or other parameters), but out-of-band data can be provided.


Even better than that is to stop using shell=True altogether. Consider:

import subprocess, glob

mergeFile=[
  'ffmpeg', '-i',
] + (glob.glob('/home/pi/Video/*') or ['/home/pi/Video/*']) + [
  '-i', '/home/pi/Audio/test.wav',
  '-acodec', 'copy',
  '-vcodec', 'copymap', '0:v',
  '-map', '1:a1',
  '/home/pi/Test/output.mkv' 
]
subprocess.Popen(mergefile)

The or ['/home/pi/Video/*'] exists to cause the same error message you'd get with a shell if no files matching the glob exist. Obviously, you could just abort in that case as well.

Upvotes: 1

Related Questions