I am trying to make a script to delete folders that does not contain media files. The code below works but also deletes empty directories and the media could be in a sub directory of that empty folder so I do not want it deleted.
find /mnt/movies -type d '!' -exec /bin/sh -c 'ls -1 "{}"|egrep -i -q "^*\.(avi|mp4|mkv|srt)$"' ';' -exec /bin/rm -rv {} +
Example:
tree /mnt/movies/
/mnt/movies/
├── test1
│ └── 1.mp4
└── test2
└── random.txt
find /mnt/movies -type d '!' -exec /bin/sh -c 'ls -1 "{}"|egrep -i -q "^*\.(avi|mp4|mkv|srt)$"' ';' -print
/mnt/movies
/mnt/movies/test2
Above would delete /mnt/movies so would delete everything.
First, erase all the files you don't need anymore
find /mnt/movies -type f ! -name '*.mp4' ! -name '*.avi' ! -name '*.mkv' -exec rm -v {} \;
You are left with some empty directories, and some directories containing media files. Now, pretend to remove all directories:
find /mnt/movies -type d -exec rmdir --ignore-fail-on-non-empty -v {} \;
This will skip directories which are not empty, i.e. have media files.
If you don_t have Gnu rmdir (say, because you are on the Mac), use rmdir without any options, but redirect 2>/dev/null, to avoid the error messages about non-empty directories.
Related
I have many files in a folder. If I have a single file, 7z a -t7z archive1.zip -mx0 works fine. But my files are file1, file2 ... I want to archive these files separately like archive1.zip, archive2.zip ...
Note: File names are random and archive names don't necessarily be regular like archive2, archive3. All I want archive names must be parallel to file names. For example screenshot.jpg > screenshot.zip, book.pdf > book.zip
I think a good way to do this is using find :
find . -maxdepth 1 -type f -not -name "*.zip" -exec sh -c '7z a -t7z "${1%.*}.zip" -mx0 {}' sh {} \;
-maxdepth 1 is used to not enter subdirectories
-not -name "*.zip" is used to exclude archives
-exec sh -c '' sh {} is there just to be able to strip the extension from the filename
"${1%.*}.zip" transforms filename.extension into filename.zip
I need to delete directories on Linux shell which names are longer than 4 characters.
But don't count length of sub-directories.
For example:
/12345/.. <= Should be deleted
/123456/.. <= Should be deleted
/1234/12345 <= Should NOT be deleted
/1234/123456 <= Should NOT be deleted
UPDATE:
Got it:
find -maxdepth 1 -regextype posix-egrep -type d -regex '.*[^/]{4}' -exec rm -rf {} +
To delete all directories with 5 or more characters in bash, you could do :
rm -rf ?????*/
The expression is not a regular expression, but a glob pattern that uses a set of wildecard characters to specify a filename or path.
Basically, if you want to keep your directories with 4 characters or less, you want to remove everything with 5 or more, hence the 5 ? and single *. The / indicates the directory.
man bash
* :: Matches any string, including the null string. When the globstar shell option is enabled, and * is used in a pathname
expansion context, two adjacent *s used as a single pattern will match all files and zero or more directories and subdirectories. If followed by a /, two adjacent *s will match only directories and
subdirectories.
? :: Matches any single character.
$ find .
.
$ mkdir -p {1,12,123,1234,12345,123456}/{123,12345}
$ touch foobar
$ rm -rf ?????*/
$ find .
.
./123
./123/12345 <= subdirectory with 5 or more not deleted
./123/123
./foobar <= the file is still here
./1234
./1234/12345
./1234/123
./12
./12/123
./12/12345
./1
./1/12345
./1/123
For legibility, pipe to grep then to xargs:
find . -maxdepth 1 -type d | grep '.....' | xargs rm -rf
You can use -regextype for find.
$ pdirpath="/path/to/search"
$ find "$pdirpath" -type d -regextype posix-extended \
-regex "$pdirpath/[a-z0-9]{5,}" -exec rm -rf {} \;
Above will remove directories that are,
/path/to/search/fooba
/path/to/search/12345
/path/to/search/foobar
NOT
/path/to/search/foobar/12345
/path/to/search/1234
find -maxdepth 1 -type d -name '?????*' -delete
It works for deeper nested dirs too, if you don't want to restrict yourself to -maxdepth 1.
Else
rm -rf ?????*/
is of course more brief and elegant. My first idea, rmdir, of course only works with empty dirs. I didn't think about that.
Use
find -maxdepth 1 -type d -name '?????*' -ls
before issuing the delete option, since it is irreversible. And backup often, if using find ... -delete on a regular basis. :)
I have a huge directory that contain a lot of subdirectory. But some subdirectory's name are number or strange letter like β or some other strange things.
The directory looks like this:
/
/a,/b,/1,/0,/$,/β
/a/c,/1/a,/b/β
The depth of the directory are 3, and I want to remove all the directory those names that are not in the 26 letters (a-z). Remove ./1, ./$, ./β ... and /a/1, /b/β, /a/b/2.
I try combine find and grep and parallel (A gnu xargs)
the grep works weird, if i use grep [a-z], it will also contain the strange letter, for example , a with a circle on the top.
So , i wirte this:
find . -type d -maxdepth 2|grep -v '\/[a|b|c|d|e|f|g|h|i|j|K|l|m|n|o|p|q|r|s|t|u|v|w|x|y|z]+/[a|b|c|d|e|f|g|h|i|j|K|l|m|n|o|p|q|r|s|t|u|v|w|x|y|z]+'|parallel -X -r rm -r
But it just removes all the files! The grep output contain the . directory and subdirectory like /p which I do not want to delete, but I think according to the regex it should not be contain.
Why does that happen?
And how can I remove those directory?
find itself can use regex, why not use that:
find . -maxdepth 2 -type d ! -iregex '.*/[a-z]+' -exec rm -r {} \;
Notes:
-iregex : case insensitive regex
-exec : executes a command
You can use Bash's special globbing features:
$ cd -- "$(mktemp --directory)"
$ mkdir a b 1
$ touch 0 '$' β a/c 1/a b/β
$ ls -R .
.:
'$' 0 1 a b β
./1:
a
./a:
c
./b:
β
$ shopt -s extglob globstar
$ rm -r **/!([a-z])/
$ ls -R .
.:
a b
./a:
c
./b:
You can use ls -d instead of rm -r to check which files will be deleted before going through with it.
I have a shell command that I run to scan my server and list all files with the name temp_file_14 in the /home directory tree as follows:
find /home . -name "temp_file_14" -exec ls -lh {} \;
I would like to change this command to have it physically delete the "found" files instead of listing them. Can someone help me with what the command should look like to perform a delete task instead of a list task?
Thanks.
This should work:
find . -name "temp_file_14" -exec rm -rf {} \;
Or this one:
find . -type f -name "temp_file_14" -exec rm -f {} \;
This list of files:
FILE0001
FILE0002
FILE0003
FILE0004
FILE0005
FILE0006
FILE0007
FILE0008
FILE0009
FILE0010
I want to delete all except the following:
FILE0001
FILE0008
FILE0010
How do I do this expression?
There can be a very time-consuming expression, because the files are large.
There are other files in that directory. And that can not be affected or removed. Even in the same pattern names.
Example:
FILE0001.1
FILE0002.2
bash patterns (http://www.gnu.org/software/bash/manual/bashref.html#Pattern-Matching)
shopt -s extglob
echo rm FILE00!(01|08|10)
remove the "echo" if you're satisfied.
GLOBIGNORE="FILE0001:FILE0008:FILE0010"
echo rm *
Something like this should do the trick assuming all the files are in the same directory that you execute the command and there are no other files or paths that you need to exclude:
find . ! -name 'FILE0001' ! -name 'FILE0008' ! -name 'FILE0010' -exec rm {} /dev/null \;