2

I'm trying to do as the title states. I have a server with a daily rotating movie list while I'm low on storage. I have a script that goes through and deletes the oldest .mp4. I'm left with left over files that were related to that movie just taking up space. I'd like to delete the entire folder.

Currently this is the code I have:

#Finds oldest *.mp4 and deletes it.
stat --printf='%Y %n\0' "$dir"/New_Movies/*/*.mp4 | sort -z  | sed -zn '1s/[^ ]\{1,\} //p' | xargs -0 rm

The following is my failed attempt at finding directories that do not include *.mp4 nor have "!" in the directory name. Example name: "!Action".

for d  in "$dir"/New_Movies/*/; do 
 if ! [ -e "*!*" ]; then
      [ -f "$d"*.mp4 ] || printf '%s\n' "$d"
  fi
 done

While testing, I get 3 different outputs, one each time it's run.

Run 1: It gives me the correct directories as well as all the directories containing "!" (They are shortcuts so I assume they look empty).

Run 2: Same as above but a lot of "-bash: [: too many arguments " between each printf.

Run 3: Breaks the code and doesn't run.

After: Repeats from run 1-3 in order over and over.

Example of directory:

/New_Movies/

/New_Movies/*/index.php

/New_Movies/foo/foo.mp4, foo.jpg, foo.xml

/New_Movies/bar/bar.jpg, bar.xml

After running the script I should only have /New_Movies/foo and its contents left.

3
  • Sorry, what does ! [ -e "*!*" ] suppose to do? Nov 20, 2019 at 21:19
  • I'm looking now for it, but *!* seems to get expanded (the history of commands), so I don't think it's doing what you think it's doing. That's why you get different results every time. Nov 20, 2019 at 21:34
  • My idea was it should look at the code as "anything/!anything" in the directory name. It was more so a test that I hoped would work. I now see that it makes no sense. I actually gave up and just wrote a script in PHP for this, I understand it way better.
    – RobertW
    Nov 21, 2019 at 3:39

3 Answers 3

2

Inside a script, where ! history expansion is disabled by default, you should be able to match directories whose names do not contain ! using a simple shell glob: either *[^!]* or *[!!]* (in which the first ! is POSIX negation).

There are several ways to test for the "directories that do not include *.mp4" condition; one that comes to mind is to use another glob with the shell set builtin, and test the resulting number of positional parameters $#.

Putting it together:

#!/bin/bash

shopt -s nullglob

for d in ./*[^!]*/; do
  set -- "$d"/*.mp4
  if [ $# -eq 0 ]; then
    printf '%s\n' "$d"
  fi
done

This approach should work in an interactive shell if you either disable history expansion, or escape the ! character in th glob i.e. *[^\!]*


Note: your title refers to directories starting with “!” but in the text you mention directories containing "!". I've assumed the latter case, but if you want to exclude only the former then remove the leading * from the glob.

1
  • *[^!]* is for filenames that contain at least one character other than !. You need ^*!* (zsh -o extendedglob) or !(*!*) (ksh, bash -O extglob) for filenames that don't contain !. [!!]* can be used POSIXly for filenames that don't start with ! (technically that's for filenames that start with a character other than !, but since filenames must have at least one character (well, 1 byte), that should be equivalent). Jan 17, 2022 at 16:08
1

First of all, I think your approach is very dangerous because you are searching and basing a delete operation of results of something not found. It would be way safer and beneficial if you appended this check to the script that checks and deletes the oldest mp4 file.

Nevertheless, here is a script that will get you what you need. I included a significant number of lines for logging and debugging purposes so you can see what is being checked, when, and how each folder gets categorized. Delete later on to reduce redundancy.

#!/bin/bash
# TO USE NAME IT script_check_dirs.sh and place it in the top directory
# RUN SOMETHING ALONG THE LINES OF:
#find . -mindepth 1 -type d -exec ./script_check_dirs.sh {} \;


bn=$(basename $1);     #FOLDER NAME VARIABLE
echo $bn >> dir_list;  #LOG FILE LISTING ALL FOLDERS

if [[ $bn == *\!* ]] ;   #FIRST CHECK FOR SYMBOL IN FOLDER NAME
  then
  echo -e "\n DIRECTORY:$bn -" DONT CHECK directory "$bn" ;
  echo $bn >> dir_list_good ; #APPEND TO LOG FILE LISTING FOLDERS TO KEEP
else 
  echo -e "\n DIRECTORY:$bn  -- CHECKING DIRECTORY $bn because it does not have ! in its name "; 
  f_v=$(find $bn -type f | grep -i "mp4" ); 
    if [[ $? -eq 0 ]] ; 
    then 
    echo -e "\t" FOUND MP4 FILES in $bn; 
    echo -e "\t\t" $f_v ; 
    echo -e "\t" NO - DONT DELETE $bn ; 
    echo $bn >> dir_list_good;    #APPEND TO LOG FILE LISTING FOLDERS TO KEEP
   else 
   echo -e "\t YES -- DIRECTORY $bn CAN BE DELETED because there were no mp4 files found and directory name $bn has no ! " ;
   echo $bn >> dir_list_del;  #APPEND TO LOG FILE LISTING FOLDERS TO DELETE
  fi ;
fi

Then if you can examine the three dir_* created, or just the full list and the list that should be removed you will see something like:

$ paste dir_list dir_list_del > list_formatted
$ awk ' BEGIN{printf "%-25s | %s\n","ALL","DELETE"; s=sprintf("%70s","");gsub(/ /,"-",s);print s}{printf "% -25s| %-s\n",$1,$2}' < list_formatted
ALL                      | DELETE
------------------------------------------------------------------------
!node_test3              | node_test2
node_test2               | node_test4
node_test4               | 
node_test1               | 
!node_test0              | 

1

In zsh to find the directories whose name doesn't contain ! and that contain no .mp4 regular files:

set -o extendedglob
typeset -Ua dirs=(^*!*(N/^e['()(($#)) $REPLY/*.mp4(N.Y1)']))

To delete the directory (excluding those whose name contains !) that contains the oldest mp4 file:

set -o extendedglob
rm -rf -- ^*!*/*.mp4(.om[1]:h)

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .