Remove a bunch of directories from one location based on a list of directories in another location? - linux

I have two directories in totally different places in the filesystem:
/path1/dir1/*
/path2/dir2/*
dir1 has a list of subdirectories and dir2 has a similar list of subdirectories, some of which are also in dir1
I'd like a command that can use a list of the subdirectories that are currently in dir1 and if they exist in dir2, delete them.
I was able to output a list of the subdirectory names using the find command and sed together like this:
find $PWD -maxdepth 1 -type d | sed -e 's\^/path1/dir1///g' and that will output:
subdir1
subdir2
subdir3
but I don't know how to then feed that into a command to delete (recursively) those subdirectories from another location. Do I need to use awk or xargs or something?

Sounds like you want something like this:
cd /path1/dir1; find . -type d -maxdepth 1 -mindepth 1 -exec rm -rf /path2/dir2/{} \;
Replace the "rm -rf" with "echo" to see what directories it will delete before trying it :-)
The "-f" option prevents errors if the directory doesn't exist
Some versions of find (GNU?) also have "-execdir". You can use it like this:
find /path1/dir -type d -maxdepth 1 -mindepth 1 -execdir rm -rf /path2/dir2/{} \;

for dir in path1/dir1/*/
do
rm -rf path2/dir2/"$(basename dir)"
done

You could also try using find to locate the dirs and piping to awk:
find /path1/dir1/ -maxdepth 1 -mindepth 1 -type d |awk 'BEGIN{FS="/"}{system("echo rm -rf /path2/dir2/"$NF);}'
remove the "echo" in the system() call when you are sure the command is behaving properly.

Related

how to tell find command to only remove contents of a directory

I am using find to get both files and dirs inside $dest_dir and remove them:
dest_dir="$HOME/pics"
# dest_dir content:
# dir1
# dir2
# pic1
# pic2
find $dest_dir -maxdepth 1 -exec rm -rf {} \;
Expectation: remove dest_dir contents only (i. e. dir1, dir2, pic1, pic2) and not dest_dir itself
Actual result: the command removes the dest_dir too
I also tried -delete instead of the -exec rm -rf {} \; section, but it can't remove non-empty directories.
If you pass a directory name to rm -rf it will delete it, by definition. If you don't want to recurse into subdirectories, why are you using find at all?
rm "$dest_dir"/*
On the other hand, if you want to rm -rf everything inside the directory ... Do that instead.
rm -rf "$dest_dir"/*
On the third hand, if you do want to remove files, but not directories, from an arbitrarily deep directory tree, try
find "$dest_dir" -type f -delete
or somewhat more obscurely with -execdir and find just the directories and pass in a command like sh -c 'rm {}/*', but in this scenario this is just clumsy and complex.
You can use this find command:
find "$dest_dir" -maxdepth 1 -mindepth 1 -exec rm -rf {} +
Option -mindepth 1 will find all entries inside "$dest_dir" at least one level down and will skip "$dest_dir" itself.

How to find all subdirectories with a specific name and delete its contents (and NOT delete the directories themselves)

I can't seem to find a solution that works within several posts that seem to ask a similar question. This is the command that has come the closest to working which I've used as a test on test folders:
find . -iname "*Adobe Premiere Pro Video Previews*" -exec sh -c 'rm -rf {}/*' \;
The problem is that find . -iname "*Adobe Premiere Pro Video Previews*" by itself finds the subdirectories and prints them while -exec sh -c 'rm -rf {}/*' \; does the job of deleting only the contents without deleting the directory itself. But they do not work to find the directory and delete its contents when put together. What command should I use to accomplish those two tasks simultaneously?
Thanks
for dir in `find . -type d -iname "*Adobe Premiere Pro Video Previews*"`; do
find $dir -type f -delete
done
I may not be an expert in bash, but for me the following command is working :
find . -iname "*test*" -type d -exec sh -c "rm -rf {}/*" \;
#!/bin/bash
while read -r line; do
echo "Deleting CONTENTS of folder: $line"
rm -rf "$line/*"
done <<< $(find . -type d -iname "*Adobe Premiere Pro Video Previews*")
This loops through the results of find (Using -type d to only show directories so you won't run into problems if a file contains the search string) and performs an rm -rf on the contents of each result. The /* is important as without it it would delete the result directory too, instead of just its contents.

How to delete all subdirectories with a specific name

I'm working on Linux and there is a folder, which contains lots of sub directories. I need to delete all of sub directories which have a same name. For example,
dir
|---subdir1
|---subdir2
| |-----subdir1
|---file
I want to delete all of subdir1. Here is my script:
find dir -type d -name "subdir1" | while read directory ; do
rm -rf $directory
done
However, I execute it but it seems that nothing happens.
I've tried also find dir -type d "subdir1" -delete, but still, nothing happens.
If find finds the correct directories at all, these should work:
find dir -type d -name "subdir1" -exec echo rm -rf {} \;
or
find dir -type d -name "subdir1" -exec echo rm -rf {} +
(the echo is there for verifying the command hits the files you wanted, remove it to actually run the rm and remove the directories.)
Both piping to xargs and to while read have the downside that unusual file names will cause issues. Also, find -delete will only try to remove the directories themselves, not their contents. It will fail on any non-empty directories (but you should at least get errors).
With xargs, spaces separate words by default, so even file names with spaces will not work. read can deal with spaces, but in your command it's the unquoted expansion of $tar that splits the variable on spaces.
If your filenames don't have newlines or trailing spaces, this should work, too:
find ... | while read -r x ; do rm -rf "$x" ; done
With the globstar option (enable with shopt -s globstar, requires Bash 4.0 or newer):
rm -rf **/subdir1/
The drawback of this solution as compared to using find -exec or find | xargs is that the argument list might become too long, but that would require quite a lot of directories named subdir1. On my system, ARG_MAX is 2097152.
Using xargs:
find dir -type d -name "subdir1" -print0 |xargs -0 rm -rf
Some information not directly related to the question/problem:
find|xargs or find -exec
https://www.everythingcli.org/find-exec-vs-find-xargs/
From the question, it seems you've tried to use while with find. The following substitution may help you:
while IFS= read -rd '' dir; do rm -rf "$dir"; done < <(find dir -type d -name "subdir" -print0)

Linux find all files in sub directories and move them

I have a Linux-System where some users put files with ftp in a Directory. In this Directory there are sub-directories which the users can create. Now I need a script that searches for all files in those subdirectories and moves them in a single Directory (for backup). The Problem: The Sub directories shouldn´t be removed.
the directory for the users is /files/media/documents/
and the files have to be moved in the Directory /files/dump/. I don´t care about files in /files/media/documents/, they are already handled by another script.
I already tried this script:
for dir in /files/media/documents/
do
find "$dir/" -iname '*' -print0 | xargs -0 mv -t /files/dump/
done
Instead of iterating, you could just use find. In man-page there is a "-type" option documented, so for moving only files you could do:
find "/files/media/documents/" -type f -print0 | xargs -0 mv -t /files/dump/
You also won't like to find files in /files/media/documents/, but all sub-directories? Simply add "-mindepth":
find "/files/media/documents/" -type f -mindepth 1 -print0 | xargs -0 mv -t /files/dump/
Alternatively you could also use "-exec" to skip a second command (xargs):
find "/files/media/documents/" -type f -mindepth 1 -exec mv {} /files/dump/ \;

Bash list directories that matches pattern, not children of them

I have a folder ~/anna which contains the file ~/anna/b
When I type ls ~/a* I get b.
How can I retrieve ~/anna ?
The script for recreating the scenatrio:
cd ~/
mkdir anna
touch anna/b
ls ~/a*
Expected result: anna
Actually result: b
Thanks!
To get help for the ls, just ask for it:
ls --help
You'll get list of useful options for the ls command, one of them:
-d, --directory list directory entries instead of contents,
and do not dereference symbolic links
So the solution (as stated in comments) would be:
ls -d ~/a*
Depending on your different requirements, find might be more appropriate:
find ~/ -name "a*" -type d
or
find ~/ -mindepth 1 -maxdepth 1 -name "a*" -type d
explanation:
~/: search in home dir
-mindepth 1 -maxdepth 1: only directories "one deep"
-name "a*": all files or folders starting with a
-type d: find only directories

Resources