rm -rf with missing w permissions on directories without root or chmod

I’m trying to recursively delete a directory with rm -rf, but this fails because some inner directories don’t have the w permission set. I know how to fix this with chmod. However, this requires to iterate over the whole directory twice, which can be slow.
Is there a way to remove such a directory in one go? (Assuming you have enough permissions to give yourself enough permissions)
sudo is not an option (limited user on pc in question).

Unix & Linux Asked by Koen G. on November 21, 2021

4 Answers

4 Answers

I did not do performance measurements. I just guess it makes sense to delete all the files immediately when a directory is read (because it is read completely anyway and you might risk losing already read metadata from the page cache with -depth) and change the permissions of those 1st level subdirectories then for which that is necessary. With lots of files and subdirectories it seems hard to avoid reading the same directory content again and without the files that should be much faster.

I suggest to use a wrapper script which is called for each directory. That script makes find

  • delete all files in the argument directory
  • fix the permissions of level-1 subdirectories where necessary
  • call the script for each level-1 subdirectory
set -x


test -d "$dir_path" || exit 1

declare -i tests_x=0
declare -i tests_x_limit=30
while true; do
    # there is a race condition between the -exec + and xargs
    if [ -x "$dir_path" ]; then
        sleep 1
    if [ "$tests_x" -gt "$tests_x_limit" ]; then
        exit 1

find "$dir_path" -mindepth 1 -maxdepth 1 -type f -delete -o -type l -delete 
-o -( -type d ! -perm -700 -exec  chmod u=rwx {} + , -print0 ) |
    xargs -0 -n 1 -r "$0"

And run this with /start/dir

You need rm -r afterwards as the above approach does not delete the directories (and cannot do so in a useful (i.e. faster than rm -r) way IMHO).

Independently of the command approach it may help to increase the filesystem commit time. So for ext4:

mount -o remount,commit=60 /path/to/mp

Answered by Hauke Laging on November 21, 2021

You can run a small shell in each directory to change its mode and delete its contents:

find . -depth -type d -exec sh -c 'echo "Removing $1 contents"; chmod +w "$1" ; rm -r "$1"/*' anything {} ;

Answered by xenoid on November 21, 2021

rsync with an empty dummy directory seems fine:
mkdir empty; rsync -r --delete empty/ targetdir/; rmdir empty targetdir
With a 10x repeated test on a simple example, this took 10-14s (14 was an outlier, all others took 10 or 11s),
vs. chmod -R u+w targetdir && rm -rf targetdir, which took 19-25s
and find targetdir -type d -exec chmod 755 {} ; && rm -rf targetdir, which took 12-16s but will likely deteriorate more than rsync with more complex folder structures.

Answered by Koen G. on November 21, 2021

find directory -type d -exec chmod 775 {} ;
rm -rf directory

Answered by Artem S. Tashkinov on November 21, 2021

Add your own answers!

Related Questions

Adding suffix to filename during for loop in bash

1  Asked on August 3, 2020 by mishal-ahmed


Why are aliases skipped if escaped?

2  Asked on August 2, 2020


Why can’t I type a g̃ the same way I type ñ?

1  Asked on July 29, 2020 by mmaluff


Custom logrotate with hostnames

0  Asked on July 29, 2020 by gwynn


Ask a Question

Get help from others!

© 2021 All rights reserved.