1

I'm using CentOS 7. In a specific directory, I want to delete all the "*.log" files except the newest one. I tried this

[rails@server ~]$ ls -t ~/.forever | tail -n +2 | xargs rm --
rm: cannot remove ‘pids’: No such file or directory
rm: cannot remove ‘5QEM.log’: No such file or directory
rm: cannot remove ‘sock’: No such file or directory
rm: cannot remove ‘8BVT.log’: No such file or directory
rm: cannot remove ‘lf4N.log’: No such file or directory
rm: cannot remove ‘Jf8F.log’: No such file or directory
rm: cannot remove ‘H1UG.log’: No such file or directory
rm: cannot remove ‘sNbx.log’: No such file or directory
rm: cannot remove ‘D30J.log’: No such file or directory
rm: cannot remove ‘_yj1.log’: No such file or directory
rm: cannot remove ‘Tz9c.log’: No such file or directory
rm: cannot remove ‘ur0M.log’: No such file or directory
rm: cannot remove ‘pX6o.log’: No such file or directory
rm: cannot remove ‘8P_i.log’: No such file or directory
rm: cannot remove ‘kBX_.log’: No such file or directory
rm: cannot remove ‘n4Ot.log’: No such file or directory
rm: cannot remove ‘VVdY.log’: No such file or directory
rm: cannot remove ‘T1QJ.log’: No such file or directory
rm: cannot remove ‘Zdeo.log’: No such file or directory
rm: cannot remove ‘5ejy.log’: No such file or directory
rm: cannot remove ‘dQEL.log’: No such file or directory

Not exactly sure what the output means, but the result is nothing is deleted. I'm only interested in deleting direct child files (as opposed to files in subfolders).

Dave
  • 2,548
  • Why are you piping ls -t ~/.forever into tail -n +2? tail outputs the last part of files and what you have will output the contents of the files inside starting with the 2nd line. – Nasir Riley May 15 '18 at 01:51
  • 3
    You should never try to parse output of ls : https://mywiki.wooledge.org/ParsingLs – SparedWhisle May 15 '18 at 03:28
  • @NasirRiley No, tail -n +2 without file name arguments outputs the standard input to tail starting from line 2. – Johan Myréen May 15 '18 at 05:39
  • @JohanMyréen My mistake but that's still not going to give the desired result. The output would have nothing to do with the age of the files. – Nasir Riley May 15 '18 at 11:46

3 Answers3

1

Use find :

This will delete all files and folders except the newest one in the current directory , it checks for newest file only in direct folder and not in sub-directory as you asked.

find . -maxdepth 1 ! -path .  ! -wholename `find . -maxdepth 1  -printf '%T+ %p\n' | sort -n | tail -1 | cut -d " " -f2` -exec rm -rf {} \;

and to delete only files and not folders , use -type f

find . -maxdepth 1 -type f  ! -path .  ! -wholename `find . -maxdepth 1  -printf '%T+ %p\n' | sort -n | tail -1 | cut -d " " -f2`  -exec rm -rf {} \;

Example :

$ touch {1..100}
$ echo "hello" > 89
$ find . -maxdepth 1 -type f  ! -path .  ! -wholename `find . -maxdepth 1  -printf '%T+ %p\n' | sort -n | tail -1 | cut -d " " -f2`  -exec rm -rf {} \;
$ ls
89
dgfjxcv
  • 697
  • 1
    Hey I ran your second command -- "find . -maxdepth 1 -type f ! -path . ! -wholename find . -maxdepth 1 -printf '%T+ %p\n' | sort -n | tail -1 | cut -d " " -f2 -exec rm -rf {} ;" and it deleted all of my log files. I was expecting it to leave at least one (the newest one) – Dave May 15 '18 at 13:51
  • In my answer, I added example, it is working fine my system is Ubuntu – dgfjxcv May 16 '18 at 04:47
  • You sure, you copied it correctly , I mean back-ticks , dots , any character you misplaced – dgfjxcv May 16 '18 at 04:52
1

Using zsh:

zsh -c 'rm ~/.forever/*.log(.om[2,-1])'

Unpacking that:

  • using a baseline glob of ~/.forever/*.log
  • select only regular files (.)
  • order (sort) them by modification time (this puts the newest files ahead of older files)
  • select from that ordered list the range 2 through the last (-1) -- this leaves out element #1, the newest file
  • which then falls through to being the list of files passed to rm

References:

Jeff Schaller
  • 67,283
  • 35
  • 116
  • 255
0

You're listing the names in the .forever directory, but execute the rm command one level up. Hopefully you didn't have important files going by the same names there.

If you're going to put this into a script, it might be easiest to just cd into the directory where you want to remove the files, but prepending the directory name in the xargs call is also an option.

Of course, the cautionary comment about not using the output of ls is valid, but depending on the file names in your case you might get away with it.