How do I delete the contents of a directory if there are spaces in the path? – A server stack is the collection of software that forms the operational infrastructure on a given machine. In a computing context, a stack is an ordered pile. A server stack is one type of solution stack — an ordered selection of software that makes it possible to complete a particular task. Like in this post about How do I delete the contents of a directory if there are spaces in the path? was one problem in server stack that need for a solution. Below are some tips in manage your linux server when you find problem about linux, bash, find, , .
find -name "lastStable" -o -name "lastSuccessful" -exec sh -c "sudo rm -rv {}/*" {} ;
As you can see from the above command, I am going through and deleting the contents of the lastStable
and lastSuccessful
directories, but leaving those folders behind. However in the find
, I may end up with paths with spaces such as:
/promotions/Production Development Environment/lastStable
How do I get my find script to handle these paths with spaces within them as well?
See this previous unix.se question: “Is it possible to use find -exec sh -c
safely?”.
The reason the current attempt is failing is that it substitutes the matched file path directly in the argument to sh -c
; thus if the matched file path is “/promotions/Production Development Environment/lastStable”, it’d run the equivalent of:
sh -c "sudo rm -rv /promotions/Production Development Environment/lastStable/*" '/promotions/Production Development Environment/lastStable'
(the path is included twice because {}
occurs twice in the arguments to -exec
.) The shell then performs word splitting on the command it’s been given, and runs the equivalent of:
sudo rm -rv '/promotions/Production' 'Development' 'Environment/lastStable'/*
…which isn’t what you wanted at all.
But note that the second occurrence of {}
in the -exec
string didn’t get word-split, and you can take advantage of this:
find -name "lastStable" -o -name "lastSuccessful" -exec sh -c 'sudo rm -rv "$0"/*' {} ;
Note the "$0"
instead of {}
(so the shell will do the substitution and do it without word-splitting), and the single-quotes around the subcommand (so $0
doesn’t get interpreted before it’s passed to the shell). This results in the equivalent of:
sh -c 'sudo rm -rv "$0"/*' '/promotions/Production Development Environment/lastStable'
and then the shell replaces $0
with the next argument to the shell command, giving:
sudo rm -rv "/promotions/Production Development Environment/lastStable"/*
which is (as I understand it) exactly what you want.
Try:
find . -path "*/lastSuccessful/*" -o -path "*/lastStable/*"
If that looks likes its going to select all the files/directories inside of the selected paths.
Note it must never select a path where “lastStable” or “lastSuccessful” is the last element of the directory path.
Then you can change the command to
find . -path "*/lastSuccessful/*" -delete -o -path "*/lastStable/*" -delete
Which will remove all the subdirectories inside of those paths.
This works because -path
matches the entire path evaluating it as one string but still honours globbing patterns. The -delete
will perform the necessary removal mechanism for the file that matches (rmdir or unlink). It should not need special treatment (spaces, etc) because you are not passing the request to the shell (which would normally expand characters like spaces or stars).
For anyone wanting to know how I was able to delete folder contents but keep the folder and also handle spaces, here is how I did it:
find $PWD -name "lastSuccessful" -o -name "lastStable" -type d -not -empty -print0 | while read -d $' ' path; do cd "$path"; ls -1 | xargs sudo rm -fvr; done
What it does: Finds the full path of the directory I am searching. CDs to that directory and lists the files, then deletes all those files/folders.
Try rm --
or use find -inum
or pipe it to a ls -i
to get the inode #,
then rm -i $inode#