1

I'm trying to create a bash script that trashes the oldest files in a directory with a variable setting the amount of files to retain.

My first step was to count the number of files older than a set number of 10 newest files to be retained:

#!/bin/bash
# How many files in the current directory are older than the retained files
olderThanRetain=$(find -maxdepth 1 -type f | sort -r | sed -e '1,10d' | wc -l)
echo $olderThanRetain

Works fine.

But when I try and set a variable for the number of files to be retained:

#!/bin/bash
retain=10
# How many files in the current directory are older than the retained files
olderThanRetain=$(find -maxdepth 1 -type f | sort -r | sed -e "1,(( $retain ))d" | wc -l)
echo $olderThanRetain

But this gives me the error:

sed: -e expression #1, char 3: unexpected `,'

What have I missed?

Broadsworde
  • 4,132
  • 4
  • 28
  • 45

1 Answers1

1

As comma is not a special character in bash there’s not need to quote this expression at all, you can simply use:

sed 1,${retain}d

To avoid problems with strange filenames (imagine a filename with a newline), use 0 as the line delimiter. Also I‘m not quite sure what you’re sorting there, to reversely sort by last access time I‘d do:

find -maxdepth 1 -type f -printf "%A@ %p\0" | sort -zr | sed -z 's/[^ ]* //;'1,${retain}d

You can change 0 to newline with tr \\0 \\n. To count zero-delimited lines you can use tr -cd '\0' | wc -c, see Count nul delimited items in file · U&L.

Explanations

  • find -maxdepth 1 -type f -printf "%A@ %p\0" – find every file (-type f) in the current directory without searching subdirectories (-maxdepth 1) and print "%A@ %p\0" (without a newline!) for it.
    %A@ is replaced by the file’s access time in seconds since epoch, %p by the file name and \0 by the null character, see man find/EXPRESSION/ACTIONS/-printf for the full list of escapes and directives.
  • sort -zr – sort zero-delimited data in reverse order
  • sed -z 'a;b – run the sed expressions a and b on every entry with zero as the entry delimiter
    You only need to quote characters special to the shell, see my post on quoting here. In fact in this case the only thing you need to quote is ; (by escaping or with single or double quotes), so sed -z s/[^ ]* //\;1,${retain}d is fine as well.
    • s/[^ ]* //substitute the first string not containing the space character (= everything until the first space character) and the space character that follows it with nothing (= delete it)
    • 1,${retain}d – delete the first $retain entries
dessert
  • 39,982