Intro
On Linux, I'll often use something like this to see the recently changed files in a directory with many files:
ls -t | head
I can do the following in PowerShell which is similar:
Get-ChildItem | Sort-Object -Property LastWriteTime | Select-Object -Last 15
That's a bit long so I then have the following in $PROFILE
:
function Recent ()
{
Get-ChildItem | Sort-Object -Property LastWriteTime | Select-Object -Last 15
}
And maybe also:
Set-Alias lst Recent
or
Set-Alias ls-t Recent
as a shorter variant.
Question
Is there a built-in way to list the recently changed files that's more concise than the approach I've shown above?
Is there some other best practice that y'all would recommend?
CodePudding user response:
As already presented in the comments, You can go from :
Get-ChildItem | Sort-Object -Property LastWriteTime | Select-Object -Last 15
to
gci | Sort-Object LastWriteTime |Select -l 15
What is at play ?
- gci is an alias for
Get-ChildItem
. To view all aliases available, you can typeGet-Alias
in your current session. Sort-Object LastWriteTime
make use of positional arguments. When an unnamed argument is given to a Powershell cmdlet, it is mapped to the first positional parameter.Select -l 15
-l
stand for-last
. This work because when getting a parameter that does not exist, Powershell will attempt to map it to the closest matching parameter. In all the parameter available with theSelect-Object
cmdlet, only-last
can be matched (no other parameter for that cmdlet start with the letter L. Note that in this case,l
is not defined as an alias forlast
. It is Powershell parameter disambiguation.
Best practices
What you do in your session stay in your session. You can use aliases, parameter disambiguation as much as you please.
That being said, when developing a script or a module, you should avoid using aliases, disambiguated parameters and positional parameter altogether.
Some kind of problems that might occurs.
Parameter disambiguation might fail if the cmdlet introduce another parameter that could also be a match. For instance Get-Service -inputObject something
work well. Get-Service -in "test"
will fail as it is ambiguous. -in
can match -inputObject
but also -include
. And while Get-Service -inp "test"
would work, it is not very readable compared to simply using the full parameter name.
Aliases might not be available cross-platform. For instance, while sort
work as an alias for sort-object
in Windows, it does not in Linux (as it is a native command there). This kind of differentiation might produce unexpected results and break your script depending on context. Also, some aliases might be dropped in the future and they do make the script less readable)
Finally, positional parameters should also be avoided in scripts & modules. Using named parameter will make your scripts more clear and readable for everyone.
To summarize, while working in a session, you can use aliases, parameter disambiguation and positional parameter as you please but when working on scripts or modules, they should be avoided.
References
Select-Object [-InputObject ] [[-Property] <Object[]>] [-ExcludeProperty <String[]>] [-ExpandProperty ] [-Unique] [-Last ] [-First ] [-Skip ] [-Wait] []
A positional parameter requires only that you type the arguments in relative order. The system then maps the first unnamed argument to the first positional parameter. The system maps the second unnamed argument to the second unnamed parameter, and so on. By default, all cmdlet parameters are named parameters.
Powershell Parameter Disambiguation and a surprise
For instance, instead of saying Get-ChildItem -Recurse, you can say Get-ChildItem -R. Get-ChildItem only has one (non-dynamic) parameter that started with the letter ‘R’.. Since only one parameter matches, PowerShell figures you must mean that one. As a side note, dynamic parameters like -ReadOnly are created at run-time and are treated a bit differently.