首页 > 解决方案 > 将一行cmd转换为powershell

问题描述

EDIT2:下面的最终代码

我在转换一些代码方面需要帮助,因为我对 mkvmerge、powershell 和命令提示符非常陌生。

CMD 代码来自https://github.com/Serede/mkvtoolnix-batch/blob/master/mkvtoolnix-batch.bat for %%f in (*.mkv) do %mkvmerge% @options.json -o "mkvmerge_out/%%f" "%%f"

到目前为止我所管理的

$SourceFolder = "C:\tmp" #In my actual code, this is done using folder browser
$SourceFiles = Get-ChildItem -LiteralPath $SourceFolder -File -Include *.mkv
$SourceFiles | foreach
{
    start-process "F:\Desktop\@progs\mkvtoolnix\mkvmerge.exe"
}

我将不胜感激任何帮助,因为我在学习双方时无法理解和转换。非常感谢你。

**编辑 2:**这是我的最终工作代码。

Function Get-Folder($initialDirectory) {

    #Prompt to choose source folder
    [void] [System.Reflection.Assembly]::LoadWithPartialName('System.Windows.Forms')
    $FolderBrowserDialog = New-Object System.Windows.Forms.FolderBrowserDialog
    $FolderBrowserDialog.Description = 'Choose the video folder'
    $FolderBrowserDialog.RootFolder = 'MyComputer'
    if ($initialDirectory) { $FolderBrowserDialog.SelectedPath = $initialDirectory }
    [void] $FolderBrowserDialog.ShowDialog()
    return $FolderBrowserDialog.SelectedPath


}

Function ExitMessage 
{
#endregion Function output
Write-Host "`nOperation complete";
Write-Host -NoNewLine 'Press any key to continue...';
$null = $Host.UI.RawUI.ReadKey('NoEcho,IncludeKeyDown');
Exit;
}

($SourceFolder = Get-Folder  | select )

#Check for output folder and create if unavailable
$TestFile = "$SourceFolder" + "\mkvmerge_out"
if ((Test-Path -LiteralPath $TestFile) -like "False")
{
    new-item -Path $SourceFolder -name "mkvmerge_out" -type directory
    Write-Host 'Folder created';
}

#Checking for the presence of a Json file
$TestFile = (Get-ChildItem -LiteralPath $SourceFolder -File -Filter *.json)
if ($TestFile.count -eq 0)
{
    Write-Host 'json file not found';
    ExitMessage;
}
$TestFile = "$SourceFolder" + "\$TestFile"


#Getting the total number of files and start timer.
[Int] $TotalFiles = 0;
[Int] $FilesDone = 0;
$TotalFiles = (Get-ChildItem -LiteralPath $SourceFolder -File -Filter *.mkv).count
$PercentFiles = 0;
$Time = [System.Diagnostics.Stopwatch]::StartNew()

#Start mkvmerge process with progress bar
$mkvmergeExe = 'F:\Desktop\@progs\mkvtoolnix\mkvmerge.exe'
$JsonFile = "$TestFile" # alternatively, use Join-Path
Get-ChildItem -LiteralPath $SourceFolder -File -Filter *.mkv | ForEach-Object {
    $PercentFiles = [math]::truncate(($FilesDone/$TotalFiles)*100)
    Write-Progress -Activity mkvmerge -Status ("{0}% Completed; {1}/{2} done; Time Elapsed: {3:d2}:{4:d2}:{5:d2}" -f $PercentFiles, $FilesDone, $TotalFiles, $Time.Elapsed.Hours, $Time.Elapsed.minutes, $Time.Elapsed.seconds) -PercentComplete $PercentFiles;
    Write-Host "Processing $_"
    $f = $_.FullName
    $of = "$SourceFolder\mkvmerge_out\$($_.Name)"
    & $mkvmergeExe -q `@$JsonFile -o $of $f
    $FilesDone++
}

Remove-Item -LiteralPath $JsonFile #Remove this line if you want to keep the Json file
$PercentFiles = [math]::truncate(($FilesDone/$TotalFiles)*100)
Write-Progress -Activity mkvmerge -Status ("{0}% Completed; {1}/{2} done; Time Elapsed: {3:d2}:{4:d2}:{5:d2}" -f $PercentFiles, $FilesDone, $TotalFiles, $Time.Elapsed.Hours, $Time.Elapsed.minutes, $Time.Elapsed.seconds) -PercentComplete $PercentFiles;
ExitMessage;

标签: powershellcmd

解决方案


$mkvmergeExe = 'F:\Desktop\@progs\mkvtoolnix\mkvmerge.exe'
$optionsFile = "$SourceFolder\options.json" # alternatively, use Join-Path
Get-ChildItem -LiteralPath $SourceFolder -File -Filter *.mkv | ForEach-Object {
  $f = $_.FullName
  $of = "$SourceFolder\mkvmerge_out\$($_.Name)"
  & $mkvmergeExe `@$optionsFile -o $of $f
}

请注意,您的cmd代码假定它在当前目录中运行,而您的 PowerShell 代码通过$SourceFolder;显式传递一个目录。因此,该options.json文件也必须在 in 中查找$SourceFolder,并且传递给的输出文件路径-o必须以$SourceFoldertoo 为前缀,这是通过可扩展字符串( "...") 实现的。

需要考虑的要点:

  • for %%f in (*.mkv)在 PowerShell 中没有直接对应物;相反,您正确地使用Get-ChildItem了获取匹配文件的列表,这些文件作为System.IO.FileInfo实例返回。

    • 但是,-Include如果没有-Recurse(除非您附加\*- 请参阅此 GitHub 问题-Filter确实,并且也是更快的方法,但它有其局限性和遗留怪癖(请参阅此答案)。
  • 虽然 PowerShell 也允许您执行名称或路径存储在变量中(或指定为带引号的字符串文字)的命令,但出于句法原因,您需要&调用运算符 来调用它

  • 在传递给cmdlet的脚本块( ) 中,自动变量表示手头的管道输入对象。{ ... }ForEach-Object $_

    • $_.FullName确保System.IO.FileInfo输入实例在字符串上下文中使用时由其完整路径表示。

    • 在 PowerShell [Core] 6+ 中不再需要这个额外的步骤,System.IO.FileInfo幸好实例总是字符串化为它们的完整路径。

  • @字符前面是`(backtick),PowerShell 的转义字符,因为@- 与 in 不同cmd- 是一个元字符,即具有特殊句法含义的字符。 `@确保 the@逐字处理,因此传递给mkvmerge.

    • 或者,您可以引用参数而不是仅转义@"@$optionsFile"

    • 有关背景信息,请参阅此答案

  • 通常不需要PowerShell中包含参数"...",即使它们包含空格或其他元字符。


推荐阅读