PowerShell for rm -rf

TL;DR – Remove-Item -Recurse -Force <path>

On linuxy systems, rm -rf <path> means “remove this path and everything under it, dammit.” If the files aren’t writeable, but you own the files, it deletes them anyway.

In PowerShell, rm is aliased to Remove-Item, but it doesn’t accept -rf.

Windows Terminal> rm -rf fooRemove-Item : A parameter cannot be found that matches parameter name 'rf'.

I can call Remove-Item without -rf, and it still works, but it asks me for confirmation.

Windows Terminal> rm foo

> rm foo

Confirm
The item at C:\Users\jessi\code\jessitron\injectify\foo has children and the Recurse parameter was not specified. If
you continue, all children will be removed with the item. Are you sure you want to continue?

I can say “A” for “Yes to all” and then it does what I want.

Unless! There are files in there with do-not-write permissions. There are zillions of these in the .git directory, for instance. Sometimes I want to wipe that out and start a fresh git history. Then I get a zillion errors:

Remove-Item : Cannot remove item
C:\Users\jessi\code\jessitron\injectify\.git\objects\bf\203afb5389983253213646fa165f749fdcaf09: You do not have
sufficient access rights to perform this operation.
At line:1 char:1
+ Remove-Item -Recurse .git
+ ~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : PermissionDenied: (203afb5389983253213646fa165f749fdcaf09:FileInfo) [Remove-Item],

Here’s the secret formula:

Remove-Item -Recurse -Force <path>

Recurse is for deleting all the directories and files underneath; Force is for overcoming those permissions errors. This will get rid of .git for me.

It’s a little sad that -rf doesn’t translate to -Recurse -Force. It is not an unreasonable abbreviation. Maybe in a future PowerShell release, it will.

PowerShell equivalent of ack

Today I found a typo in some docs: “account” was misspelled as “accuont.” I want to find that in the repository. As a bash user, I tried

ack accuont

but of course that command is not found in PowerShell.

It took me a while to find the equivalent so here it is:

Select-String -Path .\**\*.md -Pattern accuont

You need to list the fileglob or else it’ll search binary files and mess up your screen.

Comma-separated lists work for both globs and patterns. Regex strings work in patterns.

Rebase on the World: personal shell choice

“Why use bash when you have PowerShell?” <– words I did not expect to hear from my own mouth.

Over the past few weeks I’ve begun learning PowerShell, and it’s an improvement over the UNIX (and family) shells, bash and ksh etc.

PowerShell is newer. It builds on what those shells did right, and then gets it more right.

The UNIX-y shell commands have this magical power of composition: you can pipe the output of one to the input of another, and chain these to build tiny programs right on your command line. One sends text to STDOUT, the next reads it on STDIN.

PowerShell does this piping, except with objects instead of lines of text. The data is structured and interrogable (I can ask it what fields it has). In bash, you output your data as text, and the next program parses that text.

Here’s an example from Chapter 1 of PowerShell in Action. In bash, the sort command can parse the piped text and sort on it. You can specify numeric sorting.

In PowerShell, the sort command works on named properties of the piped object. And it knows the type of the property, so nobody has to tell it what’s a number.

More: PowerShell standardizes parsing of command-line arguments. This gives me consistency when I use the command, and saves painful work when I write a command.

More: PowerShell gives me multiple output paths, one for data (to the next program) and another to the user who typed the command. In bash, commands like git abuse STDERR to send info back to the user.

When PowerShell was only for Windows, by far the most powerful command-line shell for me was bash (or fish or zsh, pick your favorite). Bash worked in the worlds I lived in, and that matters most. Now that PowerShell runs on Mac and Linux, it is the most powerful command-line shell for me … except for one thing.

The biggest thing bash has on PowerShell is: I already know bash. I can type stuff there and it just works. With PowerShell I have to look things up all the time.

But every time I look something up, I increase my abilities. PowerShell raises the floor I build on, compared to bash.

It is always a tradeoff between sharpening the tools we have, vs trading them in for a better model. In this case, I’ll take some slowness in the beginning for a faster top speed.

By switching, I gain advantages that the software world has created since I started programming twenty years ago. I rebase myself on the latest version of the world.

Development aesthetic: experiments

Software development is a neverending string of “What happens if I…?” Each new runtime, language, or tool is a new world with its own laws of nature. We get to explore each one with experiments.

Objective

Today I added another alias to my PowerShell $profile: echo "Good morning!" # ... Function ListFilesWithMostRecentAtBottom { Get-ChildItem | Sort-Object -Property LastWriteTime } Set-Alias ll ListFilesWithMostRecentAtBottom To use that alias in my current shell, I need to source the profile again. I googled how to do this. The first useful page said: &$profile

So I typed that. It echoed “Good morning!” but the alias did not work.

Hmm, did it not save?

I can test that. I changed the echo to “Good morning yo!” and tried again.

It printed the new text, but still didn’t get the alias.

Hmm, is something wrong with the alias?

I opened a new shell window to test it.

The new alias works in the new window. Therefore, it’s the & $profile command that is not doing what I want. Investigation I could ignore the problem and continue work in the new window. My alias is working there. But dang it, I want to understand this. I want to know how to reload my$profile in the future.

Time for more googling. The next post had a new suggestion:

. $profile I typed that, and it worked. yay! But wait, was that the old window or the new window? What if it only worked becuase I was in the new window? I want to be certain that running .$profile brings in any new aliases I just added. For a proper experiment, I need to see the difference.

Experiment

I add a new alias to my $profile, and also change the echo so that I’ll be sure it’s running the new version. echo "Good morning yo tyler!" # ... Function ListFilesWithMostRecentAtBottom { Get-ChildItem | Sort-Object -Property LastWriteTime } Set-Alias ll ListFilesWithMostRecentAtBottom Set-Alias tyler ListFilesWithMostRecentAtBottom In my terminal, I run tyler as a test case, then the command I’m investigating (.$profile), then the test case tyler again.

Now I can see the before and after, and they’re different. I can tell that . $profile has the desired effect. Now I have learned something about PowerShell. Epilogue I remove the extra tyler stuff from$profile.

As far as I can tell, & runs the script in a subshell, and . runs the contents of the script in the current shell. The . command works like this in bash too, so it’s easy for me to remember.