How to search for directories with a given pattern or string and delete them in Unix

This is probably common knowledge but I recently figured out how to use find and xargs with the pipe operator.

Say, I want to do the following:

I’m using vcr and I want to delete all the files (and directories) in test/cassettes that contain the string Stripe.

Here’s how I did it in the terminal:

# NOTE: I'm running this in my project work directory
find ./test/cassettes -name "*Stripe*" | xargs -I dir rm -rf dir

Here’s a step-by-step explanation of the command:

find ./test/cassettes

The find command expects a path to begin searching for files.

In this case, I set the path to ./test/cassettes which means find will only search for files under the ./test/cassettes directory.

Any valid file path can be passed to find.

find ./test/cassettes -name "*Stripe*"

After that, I pass the -name flag with a pattern of "*Stripe*".

The * in the pattern is a glob operator, which essentially matches everything before or after the given pattern.

In my case, the pattern would match any file or directory that contains the string Stripe.

find ./test/cassettes -name "*Stripe*" |

The | refers to the Unix pipe operator.

In summary, whatever’s on the left of the pipe operator will be sent to its right, hence the term pipe (think of a water pipe flowing from left to right).

# NOTE: I'm running this in my project work directory
find ./test/cassettes -name "*Stripe*" | xargs -I dir rm -rf dir

The xargs command is tricky to explain. What it does is it “captures” output which can then be fed to another command.

In my case, xargs would capture the output from the find ./test/cassettes -name "*Stripe*" command, and feed it to the rm -rf command.

The key here is the -I flag.

The find command I used returns a list of filenames line by line. When the -I flag is passed to xargs, it will execute the given command for each line, which is exactly what I want.

The value you pass to -I is the argument you’ll use in the command you want to execute.

In my case, each line returned from find will be stored in the dir argument, which is then plugged into the rm -rf command.

You can use any name you want for the -I argument.

To demonstrate, when I run:

find ./test/cassettes -name "*Stripe*"

I’ll get something like:

./test/cassettes/A_Stripe_Cassette.yml
./test/cassettes/Another_Stripe_Cassette.yml
./test/cassettes/Yet_Another_Stripe_Cassette.yml

I then pass the output to xargs with the pipe operator:

find ./test/cassettes -name "*Stripe*" | xargs -I dir rm -rf dir

which essentially does this:

rm -rf ./test/cassettes/A_Stripe_Cassette.yml
rm -rf ./test/cassettes/Another_Stripe_Cassette.yml
rm -rf ./test/cassettes/Yet_Another_Stripe_Cassette.yml

and wallah, my files are deleted!