TransWikia.com

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

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

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).

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
#!/bin/bash
  
set -x

dir_path="$1"

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
        break
    else
        sleep 1
    fi
    tests_x+=1
    if [ "$tests_x" -gt "$tests_x_limit" ]; then
        exit 1
    fi
done

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

deletion.sh /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!

Ask a Question

Get help from others!

© 2024 TransWikia.com. All rights reserved. Sites we Love: PCI Database, UKBizDB, Menu Kuliner, Sharing RPP