AFouquet
AFouquet

Reputation: 43

How can I use variables in long PowerShell command without breaking the command

I want to use ffmpeg to convert .m4a files in to .mp3 files.

I can do it for each single file, but that takes a lot of effort to type in.

ffmpeg -i '.\song.m4a' -ac 2 -b:a 192k '.\song.mp3'

Is there a way to do this with powershell using variables? ex:

ffmpeg -i $v -ac 2 -b:a 192k $v.mp3

The problem with this is that then the -ac flag is taken as part of the path and not of ffmpeg anymore.

Is there a way around this in powershell?
Or could this be done with an array? If I use $v=Get-ChildItem -Name and iterate over the array with a foreach loop in to the ffmpeg command.

I am very new to PowerShell and don't have a lot of experience but it seems to me that should be possible to do.

I would appreciate any help I can get.

Upvotes: 1

Views: 192

Answers (3)

Doug Maurer
Doug Maurer

Reputation: 8868

If you do just Get-Childitem -Name you would end up with song.m4a.mp3 unless you took care of that with a replace statement, etc. If you keep it as an object then you could reference the name and later the basename.

get-childitem -Filter *.m4a |
    foreach {ffmpeg -i “$($_.name)“ -ac 2 -b:a 192k “$($_.basename).mp3”}

I have not tested this so you may need to adjust the quotes.

Upvotes: 2

mklement0
mklement0

Reputation: 438208

Note:

  • Your real problem is not with -ac, but with argument $v.mp3

  • While the immediate fix would be "$v.mp3" - i.e. to simply double-quote your argument - that would result in doubled file extensions (.mp4.mp3), for which Doug Maurer's answer offers a fix.

The following focuses generally on how PowerShell interprets a command-line argument such as $v.mp3.


In order for $v.mp3 to be interpreted as the value of variable $v as a whole followed by verbatim text .mp3, you must double-quote the argument ("$v.mp3"), as shown in js2010's answer.

  • A double-quoted, interpolating string in PowerShell is called an expandable string, and the syntax rules are covered in this answer.

Unquoted arguments are often, but not always, implicitly treated like expandable strings, but a single variable reference such as $v or even a subexpression such as $($v.BaseName) or ($v.BaseName) followed by something that looks like a property access or even method call - such as $v.mp3 here - is a notable exception and is interpreted as just that:

  • Therefore, PowerShell interprets the .mp3 part as a property access: that is, it tries to return the value of a property named mp3 of the object stored in variable $v; if $v contains a string, there will be no such property, which means that the expression evaluates to $null and no argument at all is passed to the external program (ffmpeg).

  • The rules for how PowerShell treats variable references and subexpressions in unquoted command-line arguments are complex:

    • See this answer for a comprehensive overview.
    • Therefore, if you know that your argument is meant to be a string that mixes variable references and verbatim parts, it's simplest to always use double-quoting.

Upvotes: 1

js2010
js2010

Reputation: 27473

$v.mp3 doesn't seem to work. Make a variable set to 'song.mp3' instead. Or use double quotes "$v.mp3".

echoargs $v.mp3   # no output


echoargs "$v.mp3"
Arg 0 is <song.mp3>

Upvotes: 1

Related Questions