securitymyth
securitymyth

Reputation: 41

I am trying to delete to the oldest files in a directory once there are 8 files in the directory

I am trying to delete to the oldest files in a directory once there are 8 files in the directory.

ls -Ct /tmp/test/ | awk '{$1=$2=$3=$4=""; print $0}' | xargs rm

I would like it delete the output of:

ls -Ct /tmp/test/ | awk '{$1=$2=$3=$4=""; print $0}' 

but I keep getting an error showing those files don't exist. I know it is because xargs is looking in the directory I'm currently in, but i need it to look off /tmp/test/ instead. Is there any way this can be done?

Upvotes: 2

Views: 1012

Answers (6)

Yuji
Yuji

Reputation: 525

I'm going to assume that you leave 8 newest files and delete the rest.

$ mkdir test
$ cd test
$ touch "0 0"
$ for i in $(seq 1 10) ; do touch $i ;sleep 1 ; done
$ touch "a a"
$ ls -t
ls -t1 | sed -n '9,$p' | while read f; do rm "$f" ; done
$ ls -t1
a a
10
9
8
7
6
5
4

Upvotes: 1

karakfa
karakfa

Reputation: 67507

how about

$ ls -t | tail +9 | xargs rm

sort the files in time order, list select from 9th and delete. If for less than 8 files you don't want to see the rm error, just add -f option.

Upvotes: 0

kvantour
kvantour

Reputation: 26491

If you want to use , this is easily done with two commands:

$ t=$(find . -maxdepth 1 -type f -printf "%T@\n" | sort -rg | awk '(NR==9)')
$ [[ "$t" != "" ]] && find . -maxdepth 1 -type f ! -newermt "@${t}" -delete

The first command finds the 9th youngest file and picks its modification time in epoch. The second command picks all files that are not newer than this modification time. (So that is why we pick the 9th time, to keep the 8 youngest)

When you want to do it in , you can do the following:

$ files=( *(.om) )
$ (( ${#files[9,-1]} != 0 )) && rm "${files[9,-1]}"

This creates an array files which contains files (.) which are sorted (om) by modification time. Then we select the files starting at position 9 till the end. To be safe, we check first if there are files in that sublist.

Both methods presented here avoid any issues you might have with funny filenames.

Upvotes: 1

You could use:

read filename < <(ls -rt)

to know the oldest file (or directory) into the variable filename.

This line invokes ls(1) to create a list of files ordered by time (-t) reversed (-r): the first filename returned will be the oldest.

To know how many files (or directories) are there, you can use:

ls | wc -w

Hope it helps.

Upvotes: 0

tshiono
tshiono

Reputation: 22032

Assuming the filenames do not contain tabs or newlines, please try the following:

dir="/tmp/test"

while IFS= read -r line; do
    files+=( "$line" )
done < <(find "$dir" -maxdepth 1 -type f -printf "%T@\t%p\n" | sort -n -k 1 -t $'\t' | cut -f 2)

(( ${#files[@]} < 8 )) && exit
n=8

# try the following to remove the oldest n files
rm -- "${files[@]:0:$n}"

# try the following to keep the newest n files and remove older ones
m=$(( ${#files[@]} - n ))
rm -- "${files[@]:$m:$n}"

As @JamesBrown points out, it is not clear to me how many files should be removed or left. Please try either of the options above depending on your requirement.

Upvotes: 0

James Brown
James Brown

Reputation: 37424

You wrote to delete to the oldest files in a directory once there are 8 files. I'm not quite sure what you mean by that but I'm going to assume that you leave 8 newest files and delete the rest. Also, since you tagged awk, I'm using GNU awk (for stat()) for the job.

First some test material:

$ mkdir test                                                  # create test dir
$ cd test                                                     # use it
$ for i in $(seq 1 10 | shuf) ; do touch $i ;sleep 1 ; done   # touch some test files
$ ls -t                                                       # 1 possible distribution
8  10  6  7  1  2  4  9  3  5

The gawk program:

$ gawk '
@load "filefuncs"                                    # enable stat()
BEGIN {
    for(i=1;i<ARGC;i++) {                            # iterate argument files
        ret=stat(ARGV[i],fdata)                      # use stat to get the mtime
        mtimes[ARGV[i]]=fdata["mtime"]               # hash to an array
    }
    PROCINFO["sorted_in"]="@val_num_desc"            # set for traverse order to newest first
    for(f in mtimes)                                 # use that order
        if(++c>8)                                    # leave 8 newest
            cmd=cmd OFS f                            # gather the list of files to rm
    if(cmd) {                                        # if any
        cmd="rm -f" cmd                              # add rm to the beginning
        print cmd                                    # print the command to execute
        # # # system(cmd)                            # this is the actual remove command
    }                                                # by uncommenting it you admit you 
}' *                                                 # understand how the script works 
                                                     # and accept all responsibility

Upvotes: 1

Related Questions