20

I want to make a bash script to delete the older file form a folder. Every time when I run the script will be deleted only one file, the older one. Can you help me with this? Thanks

1
  • 2
    It is worth reading this article. It explains the command ls -1t | tail -n +11 | xargs rm -f
    – Vassilis
    May 24, 2019 at 21:54

4 Answers 4

27

As Kos pointed out, It might not be possible to know the oldest file (as per creation date).

If modification time are good for you, and if file name have no new line:

rm -- "$(ls -rt | head -n 1)"

(if you don't have control over the file names beware of parsing ls output)

Add the -A option to ls if hidden files are also to be considered.

Since GNU coreutils 9.0, GNU ls now has a --zero option to list file names NUL-delimited, so with those recent versions and bash or zsh as the shell, a version that would work with any file name would be:

IFS= read -rd '' file < <(ls --zero -rt) &&
  rm -- "$file"

Those newer versions also have a --time=birth which can sort by birth time on some systems and filesystems (including recent GNU/Linux ones on most native filesystems).

2
  • How to delete last 10 oldest files? as the above comment gives error for more than 1 file
    – iCyborg
    Feb 23, 2021 at 15:11
  • 1
    what if I have space or newline in file name?! nope it will crash /-: Oct 3, 2021 at 20:27
4

It looks like you're fine with deleting the oldest modified file instead of the oldest created file;

Wherever the GNU implementations of the stat, sort, sed and xargs utilities are available, I consider this to be the safest method, as it won't break on filenames containing newlines:

stat --printf='%Y %n\0' ./* | sort -zn | sed -z 's/[^ ]\{1,\} //;q' | xargs -r0 rm
  • stat --printf='%.Y %n\0' ./*: prints a NUL-separated list of the last modification's time (with as much precision as available) followed by the file's path for each non-hidden file in the current working directory, prefixed with ./ to avoid problems with filenames starting with - (-- wouldn't work for GNU stat where a file called - would still be interpreted as meaning stdin);
  • sort -zn: sorts the list numerically using NUL as the line separator;
  • sed -z 's/[^ ]\{1,\} //;q': removes the first occurrence of a string containing one or more characters other than space followed by a space from the first NUL-terminated line and quits after processing and printing the first line;
  • xargs -r0 rm: passes the NUL-terminated line to rm as an argument, only if there's such a line;
% touch file1
% touch file2
% stat -c '%.Y %n' ./*            
1447318965.123211222 ./file1
1447318965.784234234 ./file2
% stat --printf='%.Y %n\0' ./* | sort -zn | sed -z 's/[^ ]\{1,\} //;q' | xargs -r0 rm 
% ls
file2
0

To determine the oldest file according to "Access Time" or "Modify Time"?

If it is the second, then just use the following command:

rm  ls -l --sort=time  | sed -n 2p  | awk '{print $NF}'
2
  • As you noted already, ls's output can be sorted either by atime or mtime, as creation time is not supported by the kernel (and a method to remove the last created file is what the question is asking for by the way); but mostly this can break 1) On a file containing a newline in ls's output. Never parse ls. Use find. 2) On a file containing a space or a tabulation, since awk '{print $NF}' will only print the last space/tab-separated word.
    – kos
    Nov 12, 2015 at 8:18
  • The command is incorrect (tries to execute "rm" first). May 19 at 12:30
0

In zsh, working regardless of what character or non-character file names may contain:

rm -- *(Om[1])

Where Om Orders in reverse by last modification time (from oldest to newest like for ls -rt), and [1] limits the expansion to the first match.

Or:

rm -- *(-Om[1])

To consider the modification time after symlink resolution (like with the -L option of ls).

rm -- *(Om[1]^/)

to exclude the files of type directory (which rm can't remove without -r anyway), with again a - prefix if you want that type and the age to be considered after symlink resolution. See also the D qualifier to also consider hidden files, or . for regular files only.

In bash or any other shell, just use zsh -c 'those codes above'.

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .