When I try to run:
mv test.txt test2.txt test-files
Returns the error:
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
However, if I simply move the files one at a time with
mv test.txt test-files
mv test2.txt test-files
Then it moves the files, but this seems tedious if I had more than two files.
Is there any possible way to move multiple files at once to a specific location?
I've tried mv t*.txt test-files which works, but the files I want to actually move are index.html and style.css
CodePudding user response:
Note: As your error message reveals, mv is a built-in alias of PowerShell's Move-Item cmdlet (albeit only on Windows) - see the bottom section for why this is problematic.
Mathias R. Jessen provided the crucial pointer in a comment:
Multiple source paths must be passed as an array to Move-Item's -Path or -LiteralPath parameter, which with directly specified paths requires separating them with ,:
# Note the "," separating the source file names.
Move-Item -LiteralPath test.txt, test2.txt -Destination test-files
I've used named arguments above, i.e. I've preceded the arguments with the names of their target parameters.
PowerShell also supports positional parameter binding:
Move-Item test.txt, test2.txt test-files
This works, but note that it isn't fully equivalent to the above, because the first positional argument - test.txt, test2.txt binds to the -Path parameter, not -LiteralPath:
- It doesn't make a difference here, because the file names at hand contain no wildcard characters.
- However, if your literal file names happen to contain
[(e.g.,test[2].txt), binding to-Pathwouldn't work as expected.
Discovery of whether a cmdlet's parameters support arrays:
You can discover whether a given parameter supports arrays by looking at its syntax diagrams, which are part of the brief help that is displayed when you pass the standard -? switch; you can also display them in isolation with Get-Command -Syntax Move-Item, for instance.
Using Get-Help, you can even ask for details about specific parameters, using -Path as an example:
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[]> denotes the parameter's type, which in this case is an array ([] of System.String ([string]) instances. In other words: [] following a parameter type implies that arrays are supported.
However, a given cmdlet can choose to also support passing multiple arguments individually to an array-typed parameter (of necessity only one parameter can support this per cmdlet), declared with a [Parameter()] attribute whose ValueFromRemainingArguments property is set to $true:
An example is Write-Output, whose (one and only positional) -InputObject parameter is typed System.Management.Automation.PSObject[], but also has ValueFromRemainingArguments set, so that the following two calls are equivalent:
# 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
Note:
Unfortunately, the help does not reveal the presence of
ValueFromRemainingArguments- neither in the parameter's detailed view withGet-Help ... -Parameter ..., nor, typically, in a parameter's description.While programmatic discovery is possible, it is nontrivial:
# -> 'InputObject' (Get-Command Write-Output).Parameters.Values. Where({ $_.Attributes.ValueFromRemainingArguments -contains $true }).Name
Another example is Write-Host, whose -Object parameter behaves the same way. However, what is unusual about this parameter is that its type is -Object <System.Object>, i.e. it doesn't explicitly reveal that it accepts arrays; however, it does; technically, this possible, due to System.Object being capable of storing any data type, including arrays (collections). It is only the plural in the parameter's description that hints at the fact that -Object accepts arrays: "Objects to display in the host."
Alias-naming considerations:
That mv is a built-in alias for Move-Item (on Windows only)[1] is problematic. More broadly, all aliases named for internal commands of a different shell (e.g., cmd.exe's dir) or, as in this case, for external programs (possibly a different platform's) are problematic, because the syntax of these commands / programs usually differs fundamentally from PowerShell's syntax.
- Case in point: the
mvcommand in your question would work with the Unix-platform/bin/mvutility.
It is better to use PowerShell own aliases, whose names are formed methodically from the approved verb part of the command being aliased, with each approved verb having its official abbreviation, e.g., m for Move-. The abbreviation for the noun part isn't standardized, but using the initial letter stands to reason, e.g. i for Item.
- In PowerShell (Core) 7 , you can discover the verb abbreviation via
Get-Verb(output columnAliasPrefix), e.g.,Get-Verb Move; in Windows PowerShell you'll need to consult the "approved verb" link above.
And, indeed, mi is another built-in alias for Move-Item, as the following discovery command based on Get-Alias reveals:
PS> Get-Alias -Definition Move-Item
CommandType Name Version Source
----------- ---- ------- ------
Alias mi -> Move-Item
Alias move -> Move-Item
Alias mv -> Move-Item # WINDOWS ONLY
The big advantage of such aliases - aside from not pretending to be something they're not - is that their methodic naming makes it easier to remember and possibly even guess their names; e.g.,
gcforGet-Contentand, asGet-Alias -Definition Get-Aliasreveals,galforGet-Alias.Name conflicts with external programs can still occur, but are less likely. E.g.
scforSet-Contentshadows the nativesc.exeutility (for controlling services), which is the reason it was - somewhat controversially - removed from PowerShell (Core).
[1] On Unix-like platforms, the mv alias isn't defined, so as not to shadow the external, platform-native /bin/mv program.
