Delete all files except the newest 3 in bash script

前端 未结 11 1433
情深已故
情深已故 2020-12-05 18:06

Question: How do you delete all files in a directory except the newest 3?

Finding the newest 3 files is simple:

ls -t | head -3


        
相关标签:
11条回答
  • 2020-12-05 18:28

    As an extension to the answer by flohail. If you want to remove all folders except the newest three folders use the following:

    find . -maxdepth 1 -mindepth 1 -type d -printf '%T@\t%p\n' |
     sort -t $'\t' -g | 
     head -n -3 | 
     cut -d $'\t' -f 2- |
     xargs rm -rf
    

    The -mindepth 1 will ignore the parent folder and -maxdepth 1 subfolders.

    0 讨论(0)
  • 2020-12-05 18:28

    Below worked for me: ( Cheers

    0 讨论(0)
  • 2020-12-05 18:35

    The following looks a bit complicated, but is very cautious to be correct, even with unusual or intentionally malicious filenames. Unfortunately, it requires GNU tools:

    count=0
    while IFS= read -r -d ' ' && IFS= read -r -d '' filename; do
      (( ++count > 3 )) && printf '%s\0' "$filename"
    done < <(find . -maxdepth 1 -type f -printf '%T@ %P\0' | sort -g -z) \
         | xargs -0 rm -f --
    

    Explaining how this works:

    • Find emits <mtime> <filename><NUL> for each file in the current directory.
    • sort -g -z does a general (floating-point, as opposed to integer) numeric sort based on the first column (times) with the lines separated by NULs.
    • The first read in the while loop strips off the mtime (no longer needed after sort is done).
    • The second read in the while loop reads the filename (running until the NUL).
    • The loop increments, and then checks, a counter; if the counter's state indicates that we're past the initial skipping, then we print the filename, delimited by a NUL.
    • xargs -0 then appends that filename into the argv list it's collecting to invoke rm with.
    0 讨论(0)
  • 2020-12-05 18:36
    ls -t | tail -n +4 | xargs -I {} rm {}
    

    If you want a 1 liner

    0 讨论(0)
  • 2020-12-05 18:37
    ls -t | tail -n +4 | xargs -I {} rm {}
    

    Michael Ballent's answer works best as

    ls -t | tail -n +4 | xargs rm --
    

    throw me error if I have less than 3 file

    0 讨论(0)
  • 2020-12-05 18:40

    Recursive script with arbitrary num of files to keep per-directory

    Also handles files/dirs with spaces, newlines and other odd characters

    #!/bin/bash
    if (( $# != 2 )); then
      echo "Usage: $0 </path/to/top-level/dir> <num files to keep per dir>"
      exit
    fi
    
    while IFS= read -r -d $'\0' dir; do
      # Find the nth oldest file
      nthOldest=$(find "$dir" -maxdepth 1 -type f -printf '%T@\0%p\n' | sort -t '\0' -rg \
        | awk -F '\0' -v num="$2" 'NR==num+1{print $2}')
    
      if [[ -f "$nthOldest" ]]; then
        find "$dir" -maxdepth 1 -type f ! -newer "$nthOldest" -exec rm {} +
      fi
    done < <(find "$1" -type d -print0)
    

    Proof of concept

    $ tree test/
    test/
    ├── sub1
    │   ├── sub1_0_days_old.txt
    │   ├── sub1_1_days_old.txt
    │   ├── sub1_2_days_old.txt
    │   ├── sub1_3_days_old.txt
    │   └── sub1\ 4\ days\ old\ with\ spaces.txt
    ├── sub2\ with\ spaces
    │   ├── sub2_0_days_old.txt
    │   ├── sub2_1_days_old.txt
    │   ├── sub2_2_days_old.txt
    │   └── sub2\ 3\ days\ old\ with\ spaces.txt
    └── tld_0_days_old.txt
    
    2 directories, 10 files
    $ ./keepNewest.sh test/ 2
    $ tree test/
    test/
    ├── sub1
    │   ├── sub1_0_days_old.txt
    │   └── sub1_1_days_old.txt
    ├── sub2\ with\ spaces
    │   ├── sub2_0_days_old.txt
    │   └── sub2_1_days_old.txt
    └── tld_0_days_old.txt
    
    2 directories, 5 files
    
    0 讨论(0)
提交回复
热议问题