Using Find - Deleting All Files/Directories (In Linux ) Except Any One

Using find - Deleting all files/directories (in Linux ) except any one

find can be a very good friend:

$ ls
a/ b/ c/
$ find * -maxdepth 0 -name 'b' -prune -o -exec rm -rf '{}' ';'
$ ls
b/
$

Explanation:

  • find * -maxdepth 0: select everything selected by * without descending into any directories

  • -name 'b' -prune: do not bother (-prune) with anything that matches the condition -name 'b'

  • -o -exec rm -rf '{}' ';': call rm -rf for everything else

By the way, another, possibly simpler, way would be to move or rename your favourite directory so that it is not in the way:

$ ls
a/ b/ c/
$ mv b .b
$ ls
a/ c/
$ rm -rf *
$ mv .b b
$ ls
b/

How to delete all files except directories?

find . -maxdepth 1 -type f -print0 | xargs -0 rm

The find command recursively searches a directory for files and folders that match the specified expressions.

  • -maxdepth 1 will only search the current level (when used with . or the top level when a directory is used instead), effectively turning of the recursive search feature
  • -type f specifies only files, and all files

@chepner recommended an improvement on the above to simply use

find . -maxdepth 1 -type f -delete

Not sure why I didn't think of it in the first place but anyway.

How to delete all files in a dir except ones with a certain pattern in their name?

This can be done as a one-liner, though I've preserved your variables:

#!/bin/bash
version="$(uname -r)"
dir="$HOME/Installed-kernels"

find "$dir" -maxdepth 1 -type f -not -name "*$version*" -print0 |xargs -0 rm

To set a variable to the output of a command, you need either $(…) or `…`, ideally wrapped in double-quotes to preserve spacing. A tilde isn't always interpreted correctly when passed through variables, so I expanded that out to $HOME.

The find command is much safer to parse than the output of ls, plus it lets you better filter things. In this case, -maxdepth 1 will look at just that directory (no recursion), -type f seeks only files, and -not -name "*$version*" removes paths or filenames that match the kernel version (which is a glob, not a regex—you'd otherwise have to escape the dots). Also note those quotes; we want find to see the asterisks, and without the quotes, the shell will expand the glob prematurely. The -print0 and corresponding -0 ensure that you preserve spacing by delimiting entries with null characters.

You can remove the prompts regarding read-only files with rm -f.

If you also want to delete directories, remove the -type f part and add -r to the end of that final line.

Deleting all files except ones mentioned in config file

It is considered bad practice to pipe the exit of find to another command. You can use -exec, -execdir followed by the command and '{}' as a placeholder for the file, and ';' to indicate the end of your command. You can also use '+' to pipe commands together IIRC.

In your case, you want to list all the contend of a directory, and remove files one by one.

#!/usr/bin/env bash

set -o nounset
set -o errexit
shopt -s nullglob # allows glob to expand to nothing if no match
shopt -s globstar # process recursively current directory

my:rm_all() {
local ignore_file=".rmignore"
local ignore_array=()
while read -r glob; # Generate files list
do
ignore_array+=(${glob});
done < "${ignore_file}"
echo "${ignore_array[@]}"

for file in **; # iterate over all the content of the current directory
do
if [ -f "${file}" ]; # file exist and is file
then
local do_rmfile=true;
# Remove only if matches regex
for ignore in "${ignore_array[@]}"; # Iterate over files to keep
do
[[ "${file}" == "${ignore}" ]] && do_rmfile=false; #rm ${file};
done

${do_rmfile} && echo "Removing ${file}"
fi
done
}

my:rm_all;

delete all directories except one

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.

delete all folders and files within a linux directory except one folder and all contents inside that folder

Here's one way to do it:

(cd /usr/testing/member; find . -maxdepth 1 \( ! -name . -a ! -name public \) -exec echo rm -fr {} +)

That is: cd into /usr/testing/member, find all files and directories there, without going further below, and exclude the current directory (".") and any file or directory named "public", and execute a command for the found files.

This will print what would be deleted.
Verify it looks good, and then drop the echo.



Related Topics



Leave a reply



Submit