Unix & Linux Stack Exchange is a question and answer site for users of Linux, FreeBSD and other Un*x-like operating systems. Join them; it only takes a minute:

Sign up
Here's how it works:
  1. Anybody can ask a question
  2. Anybody can answer
  3. The best answers are voted up and rise to the top

I have a directory containing files of the following name structure.


I am working on a script that will retain the the last X copies of these configuration backups per each device. What kind of select magic do I need in order to make this happen?

I was thinking BASH but I'm really language agnostic.

share|improve this question
up vote 1 down vote accepted

Wildcards expand file names in lexicographic order. Since your date format matches lexicographic order, your requirement boils down to retaining the last X matches for a wildcard (or all matches if there are fewer than X). I'll assume that your backups are the files matching $device.*, adjust the pattern as needed.

In zsh:

set -- $device.*
if [[ $# -gt $X ]]; then set -- $@{[-$X,-1]}; fi
cp -- $@ /retain/area/

In any Bourne-style shell (ash, bash, ksh, …):

set -- "$device".*
if [ $# -gt $X ]; then shift $(($#-$X)); fi
cp -- "$@" /retain/area

If what you want is in fact to remove older files, you need to act on the first matches but X (or no matches if there are fewer than X).

In zsh:

rm -f -- $files[1,-$X-1]

In other shells:

set -- "$device".*
while [ $# -gt $X ]; do
  rm -- "$1"
share|improve this answer

Taking advantage of your file names, and that ls sorts lexically by default:

ls | awk -F . '
    $1 != current_device {
        current_device = $1
        n5[$1] = n4[$1]
        n4[$1] = n3[$1]
        n3[$1] = n2[$1]
        n2[$1] = n1[$1]
        n1[$1] = $0
    END {
        for (device in n1) {
            print n1[device]
            print n2[device]
            print n3[device]
            print n4[device]
            print n5[device]

I assume the device names do not contain dots. Results likely won't be sorted

share|improve this answer
That's awfully complicated. Don't parse the output of ls; the shell can list files just fine thanks to globbing. And the awk code is oversized for what it's doing. – Gilles Feb 17 '12 at 7:43

May need some changes but:

ls <DEVICE>.* | sort -r | tail -n +<X+1> | xargs echo rm 

That will output the rm statement, remove the "echo" to just delete directly.

share|improve this answer
Don't parse the output of ls. Also, most head implementations support -n +N, which would remove the need for reversing. – Gilles Feb 17 '12 at 7:46

Your Answer


By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.