Re: powershell command missing
The brevity of *nix is because all the commands were abbreviated out of necessity. The real star here is du
/POSIX and not really Bash—just imagine what you'd have to do if du
didn't exist!
Looking at the example, it's actually not correct. Fixing it you get the below output. (Unfortunately pre
and code
tags are being horribly butchered by our vulture overlords, sorry.)
PS C:\> Get-ChildItem C:\Users\me | ForEach-Object { Echo $_.Name ; $_ | Get-ChildItem -Recurse | measure-object -property Length -sum }
...
Desktop
Count : 63
Average :
Sum : 10194386
Maximum :
Minimum :
Property : Length
...
Downloads
Count : 26
Average :
Sum : 429328707
Maximum :
Minimum :
Property : Length
...
You're wondering what the syntax is about. We can break it down.
Get-ChildItem C:\Users\me |
Pipe in all children of your user folder. In PowerShell, all pieces of data are .NET objects, and every item returned by Get-ChildItem
is fully formed. This is unlike other scripting languages that might return a string for the filename (e.g. Bash). This gives you a lot of flexibility.
ForEach-Object {
Here we iterate over the objects sent thru the pipe. This is similar to piping to read
in *nix shell, but over objects instead of strings.
Echo $_.Name ;
This writes the item name to output; echo
is an alias for Write-Output
. (And its use tells me that the OP may not be very well versed in PS...)
$_ | Get-ChildItem -Recurse |
This is my change. Here we are sending the current object in the loop (in PS it's $_
for ForEach-Object
) into Get-ChildItem
. OP's example used .
which used the current directory. We are using a pipe here instead of -InputObject
or using -Path $_.FullName
because it's shorter and should be faster.
Aside about loops: You can specify the variable if you use the foreach
statement, but you can't use statements (easily) in pipes. ForEach-Object
is a "cmdlet" and is able to process pipe input and send output, so that's why it's used here. You can also use -PipelineVariable xyz
if the thing you are piping from is a cmdlet, and this will provide the variable xyz
to the next scope in the pipe.
measure-object -property Length -sum
This consumes every object sent down the pipe, reads each Length
value, which is in this case the file's size and provides a sum.
...But this example also isn't very good. It looks nothing like du
output. We can make some changes to better emulate du
and make it more "PowerShell"-y.
PS C:\>gci C:\Users\me -pv x|%{$_|gci -r -ea 4|measure Length -s -ea 4|select Sum,@{l='Filename';e={$x.Name}}}|sort Sum -d
Sum Filename
--- --------
429328707 Downloads
10194386 Desktop
2265 Searches
I tried to make it as compact as possible, and the output looks good; here is what it would look like if el Reg didn't murder it. Funny enough, this result from SO that I looked up afterwards does essentially the same thing, though I am making use of some newer language constructs (like -PipelineVariable
via the -pv
alias). If you are curious I can explain this one too, but it will take more time. It also is not truly faithful to the du
experience, as it only shows the toplevel children including files, and does not give a grand total for the toplevel directory. Modified to do that, you would get something like this:
$x='C:\Users\me\Downloads';(gci $x -ad -r -fo -ea 4)+(gi $x)|%{$d=$_;$_|gci -r -fo -ea 4|measure Length -s|select Sum,@{l='Filename';e={$d.Name}}}|sort Sum -d
Sum Filename
--- --------
429329118 Downloads
288174446 folder 2
7952775 folder1
4964601 test
I know it looks esoteric as hell, but keep in mind I am trying to keep it short, which means using all the alises and shortcuts I can. I also must stress, we are essentially re-implementing du
here, and that's why it looks so much more verbose. If du
or an equivalent existed in PowerShell, it would be as easy as:
du | sort
which is no more verbose than in *nix. But as far as I can see there is no equivalent.
If you wanted to have an experience like that, you could take the snippet I wrote above and put it in a function/cmdlet in your PS profile, which is the PS equivalent to Bash profiles. Though, I would honestly recommend to not use it, since it's not optimized at all, and you are relying on whatever PS implementation you're using to properly handle all the duplicate objects :)