Search code examples
shellposix

delete all directories except one


So using the shell, and having a directory:

./parent
./parent/one
./parent/two
./parent/three
./parent/four

i want to do something like rm -rf parent/* in one command, but keeping one directory, for example 'four', so the end result would be

./parent
./parent/four

Solution

  • With bash you can do this with the extglob option of shopt.

    shopt -s extglob
    cd parent
    rm -rf !(four)
    

    With a posix shell I think you get to use a loop to do this

    for dir in ./parent/*; do
        [ "$dir" = "four" ] && continue
        rm -rf "$dir"
    done
    

    or use an array to run rm only once (but it requires arrays or using "$@")

    arr=()
    for dir in ./parent/*; do
        [ "$dir" = "four" ] && continue
        arr+=("$dir")
    done
    rm -rf "${arr[@]}"
    

    or

    for dir in ./parent/*; do
        [ "$dir" = "four" ] && continue
        set -- "$@" "$dir"
    done
    rm -rf "$@"
    

    or you get to use find

    find ./parent -mindepth 1 -name four -prune -o -exec rm -rf {} \;
    

    or (with find that has -exec + to save on some rm executions)

    find ./parent -mindepth 1 -name four -prune -o -exec rm -rf {} +
    

    Oh, or assuming the list of directories isn't too large and unwieldy I suppose you could always use

    rm -rf parent/*<ctrl-x>*
    

    then delete the parent/four entry from the command line and hit enter where <ctrl-x>* is readline's default binding for glob-expand-word.