如何使用 PowerShell 一次移动多个项目?

How do you move more than a single item with PowerShell at once?

当我尝试 运行:

mv test.txt test2.txt test-files

Returns错误:

Move-Item : A positional parameter cannot be found that accepts argument '.\test-files\'.
At line:1 char:1
+ mv .\test.txt .\test2.txt .\test-files\
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    + CategoryInfo          : InvalidArgument: (:) [Move-Item], ParameterBindingException
    + FullyQualifiedErrorId : PositionalParameterNotFound,Microsoft.PowerShell.Commands.MoveItemCommand

但是,如果我只是一次移动一个文件

mv test.txt test-files
mv test2.txt test-files

然后它移动文件,但如果我有两个以上的文件,这似乎很乏味。

有什么方法可以同时将多个文件移动到特定位置吗?

我试过 mv t*.txt test-files 有效,但我实际要移动的文件是 index.html 和 style.css

注意:如您的错误消息所示,mv 是 PowerShell Move-Item cmdlet 的 built-in 别名(尽管仅在 Windows 上)- 请参阅底部部分为什么这是有问题的,为什么最好使用 mi 别名。

在评论中提供了关键指针:

多个源路径必须作为数组传递给Move-Item-Path-LiteralPath 参数,直接指定路径 需要用 ,:

分隔它们
# Note the "," separating the source file names.
Move-Item -LiteralPath test.txt, test2.txt -Destination test-files

我在上面使用了 named 参数,即我在参数前面加上了它们的目标参数的名称。

PowerShell 还支持位置 参数绑定:

Move-Item test.txt, test2.txt test-files

这行得通,但请注意,它并不完全等同于上面的方法,因为第一个位置参数 - test.txt, test2.txt 绑定到 -Path 参数,而不是 -LiteralPath:

  • 这里没有区别,因为手头的文件名不包含 wildcard 个字符。
  • 但是,如果您的文字文件名恰好包含 [(例如,test[2].txt),绑定到 -Path 将无法按预期工作。

发现 cmdlet 的参数是否支持数组:

您可以通过查看其 syntax diagrams 来确定给定参数是否支持数组,这些是您传递 [= 时显示的简短帮助的一部分168=]标准-?开关;例如,您也可以使用 Get-Command -Syntax Move-Item 单独显示它们。

使用Get-Help,您甚至可以询问有关特定参数的详细信息,以-Path为例:

PS> Get-Help Move-Item -Parameter Path

-Path <System.String[]>

    Specifies the path to the current location of the items. The default is the current directory. Wildcard characters are permitted.
    
    Required?                    true
    Position?                    0
    Default value                Current directory
    Accept pipeline input?       True (ByPropertyName, ByValue)
    Accept wildcard characters?  true

<System.String[]> 表示参数的类型,在本例中是一个数组 ([] of System.String ([string]) 个实例。换句话说:[]后面的参数类型表示支持数组。

但是,给定的 cmdlet 可以选择 支持将多个参数单独传递给array-typed 参数(每个 cmdlet 必须只有 一个 参数可以支持此参数),使用 [Parameter()] 属性声明,其 ValueFromRemainingArguments 属性设置为 $true:

一个例子是 Write-Output,它的(唯一的位置)-InputObject 参数被键入 System.Management.Automation.PSObject[],但也有 ValueFromRemainingArguments 集,所以下面两个呼叫是等价的:[1]

# Single array argument that directly binds to -InputObject
Write-Output 1, 2, 3

# Multiple arguments that implicitly bind collected in an array to -InputObject
Write-Output 1 2 3

:

  • 不幸的是,帮助没有揭示ValueFromRemainingArguments的存在——既不在参数的Get-Help ... -Parameter ... 的详细视图,通常也不在参数描述中。

  • 虽然 程序化发现是可能的,但它并不平凡:

    # -> 'InputObject'
    (Get-Command Write-Output).Parameters.Values.
      Where({ $_.Attributes.ValueFromRemainingArguments -contains $true }).Name
    

另一个示例是 Write-Host,其 -Object 参数的行为方式相同。然而,这个参数的不寻常之处在于它的类型是 -Object <System.Object>,即它没有明确表明它接受 arrays;但是,确实如此;从技术上讲,这可能是因为 System.Object 能够存储 任何 数据类型,包括数组(集合)。只有参数 描述 中的复数形式暗示 -Object 接受数组:“要在主机中显示的对象。”


Alias-naming 考虑因素:

mvMove-Item 的 built-in 别名(仅在 Windows 上)[2] 是有问题的。更广泛地说,所有以 不同 shell 的内部命令命名的别名(例如,cmd.exedir) 或者,在这种情况下,对于外部程序(可能是不同的平台)有问题, 因为这些命令/程序的语法通常与 PowerShell 的语法根本不同。

  • 恰当的例子:您问题中的 mv 命令 与 Unix-platform /bin/mv 实用程序一起使用。

最好使用 PowerShell 自己的 别名,其名称是从命令的 approved verb 部分有条不紊地形成的别名,每个批准的动词都有其官方缩写,例如 m 代表 Move-名词部分的缩写没有标准化,但使用首字母是有道理的,例如i 对于 Item.

  • PowerShell (Core) 7+中,您可以通过Get-Verb(输出列AliasPrefix)发现动词缩写,例如Get-Verb Move;在 Windows PowerShell 中,您需要参考上面的“批准动词”link。

而且,事实上,miMove-Item 的另一个 built-in 别名,因为以下基于 Get-Alias 的发现命令显示:

PS> Get-Alias -Definition Move-Item

CommandType     Name                                               Version    Source
-----------     ----                                               -------    ------
Alias           mi -> Move-Item                                               
Alias           move -> Move-Item                                             
Alias           mv -> Move-Item      # WINDOWS ONLY                                       
  • 这种别名的一大优势——除了不假装是他们不是的东西——是他们有条不紊的命名使它更容易记住和 p甚至可以猜出他们的名字;例如,gc 代表 Get-Content,正如 Get-Alias -Definition Get-Alias 所揭示的,gal 代表 Get-Alias.

  • 与外部程序的名称冲突仍然可能发生,但可能性较小。例如。 sc for Set-Content 隐藏了本机 sc.exe 实用程序(用于控制服务),这就是它被从 PowerShell (Core) 中删除的原因 - 有点争议 -


[1] 由于 GitHub 问题 #5122 中描述的错误,如果您还使用 Write-Output 在 PowerShell (Core) 7+ 中的 -NoEnumerate 开关,尽管在实践中差异很少重要:Write-Output -NoEnumerate 1, 2, 3 发出单个 [object[]] 实例,正如预期的那样,而 Write-Output -NoEnumerate 1 2 3 意外输出一个 [System.Collections.Generic[object]] 实例。在 Windows PowerShell 中,有一个不同的、更严重的错误:只有形式 Write-Output -NoEnumerate 1, 2, 3 产生一个 [object[]] 数组作为单个输出对象,如预期的;相比之下,形式 Write-Output -NoEnumerate 1 2 3 甚至 Write-Output -NoEnumerate -InputObject 1, 2, 3 有效地 忽略 -NoEnumerate 开关,因此一个一个地输出元素。

[2] 在 Unix-like 平台上,mv 别名未定义,以免影响外部,platform-native /bin/mv 程序.