The script below will do exactly as you describe, it:
- lists the folders inside a directory
Looks inside each of the folders for a folder named "Recording"
- If it exists and is empty, it deletes its superior folder
- if it does not exist, it also deletes its superior folder
- files on the first level inside A will not be deleted.
In an image:
A
|
|--------123456
| |
| |----Recording
| |----a.txt
| |----b.txt
|
|
|--------635623
| |----Recording
| |
| |-------a.mp3
| |----a.txt
| |----b.txt
|
|
|--------123456
| |----Recording
| |----a.txt
| |----b.txt
|
|--------Monkey.txt
will result in:
A
|
|
|--------635623
| |----Recording
| |
| |-------a.mp3
| |----a.txt
| |----b.txt
|
|
|--------Monkey.txt
The script
#!/usr/bin/env python3
import os
import sys
import shutil
dr = sys.argv[1]
def path(*args):
return os.path.join(*args)
for d in os.listdir(dr):
try:
if not os.listdir(path(dr, d, "Recording")):
shutil.rmtree(path(dr,d))
except FileNotFoundError:
shutil.rmtree(path(dr,d))
except NotADirectoryError:
pass
To use
- Copy the script into an empty file, save it as
delete_empty.py
Run it with the (full!) directory (containinf your subdirs, A in your example) as argument by the command:
python3 /path/to/delete_empty.py /path/to/directory
That's it.
Explanation
Feeding the content of your folder "A" to the script,
os.listdir(dr)
will list its subdirectories (and files). Then:
if not os.listdir(path(dr, d, "Recording"))
will try to list the content of each of the (sub)folders, which will raise an error if the item is a file:
except NotADirectoryError
pass
or if the folder "Recording" does not exist at all:
FileNotFoundError
shutil.rmtree(path(dr,d))
If the folder "Recording" exists and is empty, the superior folder is removed:
if not os.listdir(path(dr, d, "Recording")):
shutil.rmtree(path(dr,d))
EDIT
Additionally, as requested in comments, a version that will check for multiple subdirs (names).
In case the directory contains any of the listed (un- empty) subdirs, the directory is kept. Else it will be deleted.
To use
- Copy the script into an empty file, save it as
delete_empty.py
Run it with the (full!) directory (containing your subdirs, A in your example) and the names of subdirs as arguments by the command:
python3 /path/to/delete_empty.py /path/to/directory <subdir1> <subdir2> <subdir3>
That's it.
The script
#!/usr/bin/env python3
import shutil
import os
import sys
dr = sys.argv[1]; matches = sys.argv[2:]
def path(*args):
return os.path.join(*args)
for d in os.listdir(dr):
# delete directory *unless* either one of the listed subdirs has files
keep = False
# check for each of the listed subdirs(names)
for name in matches:
try:
if os.listdir(path(dr, d, name)):
keep = True
break
except NotADirectoryError:
# if the item is not a dir, no use for other names to check
keep = True
break
except FileNotFoundError:
# if the name (subdir) does not exist, check for the next
pass
if not keep:
# if there is no reason to keep --> delete
shutil.rmtree(path(dr,d))
Note
Please first run on a test directory to make sure it does exactly what you want.
First turn on recursive globbing
shopt -s globstar
Now we can look in all directories with **
. To unset, you can use shopt -u globstar
(it's off by default, so it will be off when you open a new shell).
In all of the below, remove echo
after testing to actually create the directories.
If the end-of-tree directories are empty, you could test for emptiness and make the directory only if it is detected... something like
for d in **/; do [[ -z "$(ls -Aq "$d")" ]] && echo mkdir "$d"Texture; done
i.e. if the output of ls -A (hidden files except current and parent dir) -q (printing ? for non-printing characters)
is empty, make a directory.
But since the directories contain files, we'd better test that there are no directories
for d in **/; do [[ -z "$(find "$d" -maxdepth 1 -mindepth 1 -type d)" ]] && echo mkdir "$d"Texture; done
mindepth -1
is to stop the current directory being found... find
sees hidden files, so we know those are included. Since any character should pass the test (we only want to check the output is empty), this should be fairly safe...
A more concise way (sorry Greg) (but actually all these methods do something similarly iffy - we can just about get away with using filenames as text since we aren't actually trying to do anything with those files themselves here):
for d in **/; do (ls -Alq "$d" | grep -q '^d') || echo mkdir "$d"Textures; done
here we add the -l
flag for long output, which prints every file in the form
drwxrwxr-x 5 zanna zanna 4096 Sep 27 22:00 Dir1
we then gulp pipe that stuff into grep
to see if any of the lines starts with d
(meaning there's a directory). We don't want grep
to print any of that meaningless unreliable text, so we just check its exit status with -q
to see if it found anything. If it didn't, we make a directory (using the ||
or operator, meaning, do the next command if the last one failed). This should work, actually, even if your filenames contain horrible characters such as newlines, since ls
prints them as ?
- every line should start with a letter indicating the file type, so, probably, no kittens will die.
Best Answer
Using bash:
Initially:
Then: