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!