1

Here is a simplified version of the powershell script I'm trying to write to join some .mp4 files:

[string]$inputs = ""
$filenames = "input1.mp4", "input2.mp4", "input3.mp4"
foreach ($f in $filenames) {
    $inputs += "-i $f "
}
Write-Host $inputs
.\bin\ffmpeg.exe $inputs -filter_complex...

The write-host prints out the string like I expect, but then ffmpeg gives me an error that says:

Unrecognized option 'i input1.mp4 -i input2.mp4 -i input3.mp4 '. Error splitting the argument list: Option not found

So it looks like when the arguments are being passed to cmd.exe to be passed to ffmpeg, something is getting lost (at least that's how I think it works). I've read other questions that talk about problems with passing double-quotes in arguments, but my problem is with -. Can someone explain what is going in my case? I don't think it's an escaping issue since the second and third - look like they're being passed. Also, if I just use start-process with the -argumentList option (and prepare one big $arguments string beforehand) then everything works.

robynChill
  • 45
  • 3
  • 1
    In short: In order to programmatically pass arguments to external programs, construct an _array_, with each parameter (option) name and parameter value / positional argument (operand) becoming its own element. E.g., to execute `foo -o "bar baz"`, use `$a = '-o', 'bar baz'; foo $a`. See zett42's answer and the linked duplicate for details. – mklement0 Dec 12 '22 at 16:41

2 Answers2

2

When you use PowerShell to call a process like a command (as opposed to using Start-Process), you are not supposed to build up the command-line by low-level string concatenations like you curently do. Instead, pass argument names and values as separate array elements.

PowerShell automatically constructs the final command-line by joining tokens using space character and quotes if necessary.

$filenames = "input1.mp4", "input2.mp4", "input3.mp4"

# $inputs will be an array of strings
$inputs = foreach ($f in $filenames) {
    # Make sure to separate argument names and values.
    # This implicitly adds two elements to the $inputs array.
    '-i', $f
}
Write-Host $inputs

# PowerShell builds up the command-line from the $input array (aka splatting),
# automatically quoting values that contain whitespace.
.\bin\ffmpeg.exe $inputs -filter_complex...

As for what you have tried:

You have build a single string $inputs, that is seen by PowerShell as a single argument to be passed to ffmpeg:

-i input1.mp4 -i input2.mp4 -i input3.mp4

Because the value contains whitespace, PowerShell quotes it so the final command-line looked like this:

.\bin\ffmpeg.exe "-i input1.mp4 -i input2.mp4 -i input3.mp4" -filter_complex...

A quoted string is like a single argument token. So ffmpeg strips the first dash and takes "i input1.mp4 -i input2.mp4 -i input3.mp4" as the argument name.

zett42
  • 25,437
  • 3
  • 35
  • 72
0

I had a look, if you put a space before the '-i' it seems to work, i think this is what you want :)

[string]$inputs = ""
$filenames = "input1.mp4", "input2.mp4", "input3.mp4"
foreach ($f in $filenames) {
    $inputs += " -i $f "
}
Write-Host $inputs
.\bin\ffmpeg.exe $inputs -filter_complex...
Packet
  • 11
  • 4
  • 1
    No, this won't help, because you fundamentally cannot pass _multiple_ arguments (note that `-i` and `input1.mp4` are separate arguments in the context) via a _single string_. Use an _array_ instead. – mklement0 Dec 12 '22 at 16:43