linux - Keep a fixed number of files in a directory

06
2014-04
  • chz

    We have a Linux directory where files and directories are being added to it daily.

    We like to control this list of files and subdirectories in the directory by fixing the list to 50 most recent files and directories at any given time.

    How do we write a script to achieve this goal?

  • Answers
  • slhck

    With GNU find and sort, this gets you the 50 latest files and their timestamp from the current directory:

    find . -mindepth 1 -maxdepth 1 -printf '%T@ %p\n' | sort -n | tail -n 50
    

    Pipe these into while read to get each filename:

    find . -mindepth 1 -maxdepth 1 -printf '%T@ %p\n' |
    sort -n | tail -n 50 |
    while read -r ts file; do echo rm -rf -- "$file"; done
    

    Here, printf outputs a sortable timestamp, which the numeric sort will use. We get the oldest 50 files or directories and remove each one individually. Remove the echo in the script to actually execute the commands.

    Note that this does not work if your files/directories contain a newline in their name. Doesn't happen that often, but be careful to check. Due to the nature of read, it will also not work if there are leading or trailing spaces.

    For some more ideas, see: BashFAQ/003 – How can I find the latest (newest, earliest, oldest) file in a directory?

  • slhck

    If you need to look only at the dirs in the folder (not for subdir) then execute the script:

    #!/bin/bash
    l=$(ls |wc -l)
    n=$[$l-50]
    rm -rf `ls -1t|tail -$n`
    

  • Related Question

    linux - In a for loop, how do I echo only the current file on a single(updating) line instead of EVERY file which will produce a list?
  • SaultDon

    My first question on this stackexchange, and I am sure there will be more as I venture farther into the world of what is Linux...

    I have a for-loop in a shell-script that batch renames all files to a substring (the last n characters) of its original name.

    It will echo every iteration on a new line to eventually produce a list of all files but how do I keep that echo on a single/updating line so it doesn't produce this (sometimes large) list?

    echo "- Renaming file..."
    
    for file in `find fldr -type f`
    do
      newf=$(echo $file | rev | cut -c -6 | rev)
       mv -f $file fldr/$newpt
      echo "  * $file > $newf"
    done
    

    actual output...

    - Renaming file...
      * file1a.txt > 1a.txt
      * file2a.txt > 2a.txt
      * file3a.txt > 3a.txt
      * ...
    

    desired output...

    - Renaming file...
      * file3a.txt > 3a.txt
    

    I would like to see the one line always changing to show the current file only.

    [BONUS] How would I get it to also display the n'th file it is renaming?

    - 3 files renamed...
      * file3a.txt > 3a.txt
    

    Where n is a cumulative sum/count of the files renamed.


  • Related Answers
  • Keith

    Just change the echo line to this:

    echo -ne "\r  * $file > $newf                         "
    

    The spaces on the end clear old output from the line.