如何在PowerShell单参数中接收多文件或单目录输入
问题与解决方案:PowerShell脚本接收多文件/目录输入的参数处理
背景
我正在编写基于FFmpeg处理文件的PowerShell脚本,目标适配Windows自带的PowerShell v5.1,若无法实现则使用最新版PowerShell。为了能从「运行」或命令提示符直接执行脚本,我用批处理调用:
@echo off powershell -File .\ff.ps1 %*
这样就能从命令提示符向PowerShell脚本传递所有参数。
命令语法(命令提示符中):
> ff mp3 [可选参数] <多文件>|<单目录>
传入空格分隔的多文件时,脚本处理这些文件;传入单个目录时,处理该目录内所有文件(不含子目录)。
现有参数定义
我已经在脚本顶部定义了包含子命令的参数:
[CmdletBinding()] param( [Parameter()][Boolean]$loop = $true, [Parameter()][Boolean]$twoPass = $true, [Parameter()][Int]$height = -1, [Parameter()][Int]$width = 1280, [Parameter()][Int]$quality = 80, [Parameter()][Int]$samplerate = 48000, [Parameter()][Int]$compression = 6, [Parameter()][Int]$giType = 1, [Parameter()][Int]$fps = 24, [Parameter()][Int]$bitrate = 320, [Parameter()][String]$preset = "picture", [Parameter()][Switch]$lossless = $false, [Parameter(Position = 0, Mandatory = $true)][String]$subcmd = "" )
目前子命令能正常设置,但不知道如何添加参数接收<多文件>|<单目录>的输入。
支持的输入格式
该参数需要支持以下输入格式:
// 当前目录下单个文件 01.mp4 .\01.mp4 // 当前目录下多个文件 01.jpg 02.jpg 03.jpg 04.jpg .\01.jpg .\02.jpg 03.jpg 04.jpg // 子目录下单个文件 subdir\01.png .\subdir\01.png // 子目录下多个文件 subdir\01.png subdir\02.jpg subdir\03.webp .\subdir\01.png .\subdir\02.jpg .\subdir\03.webp // 通配符 *.png .\*.png subdir2\*.mp3 .\subdir2\*.mp3 // 多通配符(含子目录) *.png *.jpg .\*.png .\*.jpg subdir2\image_*.png subdir2\image_*.jpg .\subdir2\image_*.png .\subdir2\image_*.jpg *.png subdir2\*.png *.png .\subdir2\*.png // 当前目录下单个子目录 subdir3 .\subdir3 // 子目录中的单个目录 .\subdir3\subdir4 subdir3\subdir4 // 绝对路径 C:\another_dir
所有通配符和相对路径需要解析为绝对路径,最终得到供FFmpeg处理的完整文件列表(后续会过滤不兼容格式,此为另一问题)。
脚本使用示例(PowerShell中)
PS> ff.ps1 mp3 -bitrate 320 01.mp4 subdir\*.avi 00.webp // '00.webp'将在处理前被过滤 PS> ff.ps1 webpa -loop 0 subdir // 获取'subdir'内所有文件并过滤后处理
核心问题
如何通过单个参数接收上述格式的<多文件>|<单目录>输入,并转换为文件列表?
解决方案
1. 添加可变位置参数
在param块中添加一个可变长度的位置参数,用于收集所有剩余的输入(文件/目录/通配符):
[Parameter(Position = 1, Mandatory = $true, ValueFromRemainingArguments = $true)] [String[]]$InputPaths
Position = 1:指定该参数在子命令(Position=0)之后ValueFromRemainingArguments = $true:将所有未被其他参数匹配的输入都收集到这个数组中Mandatory = $true:确保必须传入至少一个路径
2. 解析路径并生成文件列表
添加代码块处理$InputPaths,将其转换为绝对路径的文件列表:
$fileList = @() foreach ($path in $InputPaths) { # 解析相对路径、通配符为绝对路径 $resolvedPaths = Resolve-Path -Path $path -ErrorAction SilentlyContinue if (-not $resolvedPaths) { Write-Warning "路径无效或不存在: $path" continue } foreach ($resolved in $resolvedPaths) { if (Test-Path -Path $resolved.Path -PathType Container) { # 若为目录,获取目录内所有文件(不含子目录) $filesInDir = Get-ChildItem -Path $resolved.Path -File $fileList += $filesInDir.FullName } else { # 若为文件,直接添加绝对路径 $fileList += $resolved.Path } } } # 可选:去重并排序,避免重复处理 $fileList = $fileList | Select-Object -Unique | Sort-Object
这段代码的作用:
- 用
Resolve-Path处理通配符和相对路径,转换为绝对路径 - 自动区分文件和目录:目录则遍历内部文件,文件则直接加入列表
- 对无效路径输出警告并跳过
- 可选去重排序,提升批量处理的稳定性
3. 适配PowerShell v5.1的注意事项
Resolve-Path和Get-ChildItem在v5.1中的行为与最新版一致,无需额外调整- 若需处理权限问题,可将
-ErrorAction SilentlyContinue改为-ErrorAction Stop并添加异常捕获,但静默跳过更适合批量处理场景
4. 完整参数块示例
更新后的param块如下:
[CmdletBinding()] param( [Parameter()][Boolean]$loop = $true, [Parameter()][Boolean]$twoPass = $true, [Parameter()][Int]$height = -1, [Parameter()][Int]$width = 1280, [Parameter()][Int]$quality = 80, [Parameter()][Int]$samplerate = 48000, [Parameter()][Int]$compression = 6, [Parameter()][Int]$giType = 1, [Parameter()][Int]$fps = 24, [Parameter()][Int]$bitrate = 320, [Parameter()][String]$preset = "picture", [Parameter()][Switch]$lossless = $false, [Parameter(Position = 0, Mandatory = $true)][String]$subcmd = "", [Parameter(Position = 1, Mandatory = $true, ValueFromRemainingArguments = $true)] [String[]]$InputPaths )
内容的提问来源于stack exchange,提问作者tetratheta
相关产品推荐
相关产品推荐

