删除所有文件,除了最新的3在bash脚本

时间:2023-02-14 15:42:36

Question: How do you delete all files in a directory except the newest 3?

问题:除了最新的3,如何删除目录中的所有文件?

Finding the newest 3 files is simple:

找到最新的3个文件很简单:

ls -t | head -3

But I need to find all files except the newest 3 files. How do I do that, and how do I delete these files in the same line without making an unnecessary for loop for that?

但是我需要找到除最新的3个文件以外的所有文件。如何做到这一点,以及如何在相同的行中删除这些文件,而不需要为此创建不必要的for循环?

I'm using Debian Wheezy and bash scripts for this.

我在这里使用Debian Wheezy和bash脚本。

6 个解决方案

#1


30  

This will list all files except the newest three:

这将列出所有文件,除了最新的三个:

ls -t | tail -n +4

This will delete those files:

这将删除这些文件:

ls -t | tail -n +4 | xargs rm --

This will also list dotfiles:

这也将列出dotfiles:

ls -At | tail -n +4

and delete with dotfiles:

.和删除:

ls -At | tail -n +4 | xargs rm --

But beware: parsing ls can be dangerous when the filenames contain funny characters like newlines or spaces. If you are certain that your filenames do not contain funny characters then parsing ls is quite safe, even more so if it is a one time only script.

但要注意:当文件名包含一些有趣的字符(如换行符或空格)时,解析ls可能会很危险。如果您确定您的文件名不包含有趣的字符,那么解析ls是相当安全的,如果是一次性脚本,则更是如此。

If you are developing a script for repeated use then you should most certainly not parse the output of ls and use the methods described here: http://mywiki.wooledge.org/ParsingLs

如果您正在开发用于重复使用的脚本,那么您肯定不应该解析ls的输出并使用这里描述的方法:http://mywiki.wooledge.org/ParsingLs

#2


8  

The following looks a bit complicated, but is very cautious to be correct, even with unusual or intentionally malicious filenames. Unfortunately, it requires GNU tools:

下面的内容看起来有点复杂,但是要正确使用,即使是不寻常的恶意文件名。不幸的是,它需要GNU工具:

count=0
while IFS= read -r -d ' ' && IFS= read -r -d '' filename; do
  (( ++count > 3 )) && printf '%s\0' "$filename"
done < <(find . -maxdepth 1 -type f -printf '%T@ %P\0' | sort -g -z) \
     | xargs -0 rm -f --

Explaining how this works:

解释这是如何工作的:

  • Find emits <mtime> <filename><NUL> for each file in the current directory.
  • 在当前目录中,查找发出 对每个文件的数据。
  • sort -g -z does a general (floating-point, as opposed to integer) numeric sort based on the first column (times) with the lines separated by NULs.
  • sort -g -z在第一个列(时间)的基础上,根据第一个列(时间),以空号分隔的行来做一个通用的(浮点数,而不是整数)的数值排序。
  • The first read in the while loop strips off the mtime (no longer needed after sort is done).
  • while循环中的第一个读取将删除mtime(排序完成后不再需要)。
  • The second read in the while loop reads the filename (running until the NUL).
  • while循环中的第二个读取操作读取文件名(运行到NUL)。
  • The loop increments, and then checks, a counter; if the counter's state indicates that we're past the initial skipping, then we print the filename, delimited by a NUL.
  • 循环增加,然后检查计数器;如果计数器的状态表明我们已经过了初始跳过,那么我们将打印文件名,由NUL分隔。
  • xargs -0 then appends that filename into the argv list it's collecting to invoke rm with.
  • 然后,xargs -0将文件名附加到要调用rm的argv列表中。

#3


5  

ls -t | tail -n +4 | xargs -I {} rm {}

If you want a 1 liner

如果你想要一个衬里

#4


4  

This is a combination of ceving's and anubhava's answer. Both solutions are not working for me. Because I was looking for a script that should run every day for backing up files in an archive, I wanted to avoid problems with ls (someone could have saved some funny name file in my backup saving folder). So I modified the mentioned solutions to fit my needs. Ceving's soltution deletes the three newest files - not what I needed and was asked.

这是克弗和阿努巴瓦的结合。这两种方法对我都不起作用。因为我在寻找一个应该每天运行的脚本来备份存档中的文件,所以我想避免ls的问题(有人可能在我的备份保存文件夹中保存了一些有趣的名字文件)。所以我修改了上面提到的解决方案以满足我的需要。ceval的soltution会删除这三个最新的文件——不是我需要的,而是我被要求的。

My solution deletes all files, except the three newest files.

我的解决方案删除所有文件,除了三个最新的文件。

find . -type f -printf '%T@\t%p\n' |
sort -t $'\t' -g | 
head -n -3 | 
cut -d $'\t' -f 2- |
xargs rm

Some explanation:

这里做一些解释:

find lists all files (not directories) in current folder. They are printed out with timestamps.
sort sorts the lines based on timestamp (oldest on top).
head prints out the top lines, up to the last 3 lines.
cut removes the timestamps.
xargs runs rm for every selected file.

查找列出当前文件夹中的所有文件(非目录)。他们用时间戳印出来。根据时间戳排序(最老的在上面)。头部打印出最上面的几行,直到最后三行。删除时间戳。xargs为每个选定的文件运行rm。

For you to verify my solution:

供您验证我的解决方案:

(
touch -d "6 days ago" test_6_days_old
touch -d "7 days ago" test_7_days_old
touch -d "8 days ago" test_8_days_old
touch -d "9 days ago" test_9_days_old
touch -d "10 days ago" test_10_days_old
)

This creates 5 files with different timestamps in the current folder. Run this first and the code for deleting to test the code.

这将在当前文件夹中创建5个具有不同时间戳的文件。运行第一个和删除代码来测试代码。

#5


1  

Don't use ls -t as it is unsafe for filenames that may contain whitespaces or special glob characters.

不要使用ls -t,因为它对可能包含空格或特殊手套字符的文件名不安全。

You can do this using all gnu based utilities to delete all but 3 newest files in the current directory:

您可以使用所有基于gnu的实用工具来删除当前目录中除3个最新文件之外的所有文件:

find . -maxdepth 1 -type f -printf '%T@\t%p\0' |
sort -z -nrk1 |
tail -z -n +4 |
cut -z -f2- |
xargs -0 rm -f --

#6


0  

This uses find instead of ls with a Schwartzian transform.

它使用find而不是具有Schwartzian转换的ls。

find . -type f -printf '%T@\t%p\n' |
sort -t $'\t' -g |
tail -3 |
cut -d $'\t' -f 2-

find searches the files and decorates them with a time stamp and uses the tabulator to separate the two values. sort splits the input by the tabulator and performs a general numeric sort, which sorts floating point numbers correctly. tail should be obvious and cut undecorates.

查找文件并使用时间戳对其进行修饰,并使用tabulator分隔两个值。sort通过制表符分割输入并执行一个通用的数字排序,它正确地对浮点数进行排序。尾巴要明显,切得不雅观。

The problem with decorations in general is to find a suitable delimiter, which is not part of the input, the file names. This answer uses the NULL character.

装饰品的问题通常是找到一个合适的分隔符,它不是输入的一部分,也不是文件名。这个答案使用空字符。

#1


30  

This will list all files except the newest three:

这将列出所有文件,除了最新的三个:

ls -t | tail -n +4

This will delete those files:

这将删除这些文件:

ls -t | tail -n +4 | xargs rm --

This will also list dotfiles:

这也将列出dotfiles:

ls -At | tail -n +4

and delete with dotfiles:

.和删除:

ls -At | tail -n +4 | xargs rm --

But beware: parsing ls can be dangerous when the filenames contain funny characters like newlines or spaces. If you are certain that your filenames do not contain funny characters then parsing ls is quite safe, even more so if it is a one time only script.

但要注意:当文件名包含一些有趣的字符(如换行符或空格)时,解析ls可能会很危险。如果您确定您的文件名不包含有趣的字符,那么解析ls是相当安全的,如果是一次性脚本,则更是如此。

If you are developing a script for repeated use then you should most certainly not parse the output of ls and use the methods described here: http://mywiki.wooledge.org/ParsingLs

如果您正在开发用于重复使用的脚本,那么您肯定不应该解析ls的输出并使用这里描述的方法:http://mywiki.wooledge.org/ParsingLs

#2


8  

The following looks a bit complicated, but is very cautious to be correct, even with unusual or intentionally malicious filenames. Unfortunately, it requires GNU tools:

下面的内容看起来有点复杂,但是要正确使用,即使是不寻常的恶意文件名。不幸的是,它需要GNU工具:

count=0
while IFS= read -r -d ' ' && IFS= read -r -d '' filename; do
  (( ++count > 3 )) && printf '%s\0' "$filename"
done < <(find . -maxdepth 1 -type f -printf '%T@ %P\0' | sort -g -z) \
     | xargs -0 rm -f --

Explaining how this works:

解释这是如何工作的:

  • Find emits <mtime> <filename><NUL> for each file in the current directory.
  • 在当前目录中,查找发出 对每个文件的数据。
  • sort -g -z does a general (floating-point, as opposed to integer) numeric sort based on the first column (times) with the lines separated by NULs.
  • sort -g -z在第一个列(时间)的基础上,根据第一个列(时间),以空号分隔的行来做一个通用的(浮点数,而不是整数)的数值排序。
  • The first read in the while loop strips off the mtime (no longer needed after sort is done).
  • while循环中的第一个读取将删除mtime(排序完成后不再需要)。
  • The second read in the while loop reads the filename (running until the NUL).
  • while循环中的第二个读取操作读取文件名(运行到NUL)。
  • The loop increments, and then checks, a counter; if the counter's state indicates that we're past the initial skipping, then we print the filename, delimited by a NUL.
  • 循环增加,然后检查计数器;如果计数器的状态表明我们已经过了初始跳过,那么我们将打印文件名,由NUL分隔。
  • xargs -0 then appends that filename into the argv list it's collecting to invoke rm with.
  • 然后,xargs -0将文件名附加到要调用rm的argv列表中。

#3


5  

ls -t | tail -n +4 | xargs -I {} rm {}

If you want a 1 liner

如果你想要一个衬里

#4


4  

This is a combination of ceving's and anubhava's answer. Both solutions are not working for me. Because I was looking for a script that should run every day for backing up files in an archive, I wanted to avoid problems with ls (someone could have saved some funny name file in my backup saving folder). So I modified the mentioned solutions to fit my needs. Ceving's soltution deletes the three newest files - not what I needed and was asked.

这是克弗和阿努巴瓦的结合。这两种方法对我都不起作用。因为我在寻找一个应该每天运行的脚本来备份存档中的文件,所以我想避免ls的问题(有人可能在我的备份保存文件夹中保存了一些有趣的名字文件)。所以我修改了上面提到的解决方案以满足我的需要。ceval的soltution会删除这三个最新的文件——不是我需要的,而是我被要求的。

My solution deletes all files, except the three newest files.

我的解决方案删除所有文件,除了三个最新的文件。

find . -type f -printf '%T@\t%p\n' |
sort -t $'\t' -g | 
head -n -3 | 
cut -d $'\t' -f 2- |
xargs rm

Some explanation:

这里做一些解释:

find lists all files (not directories) in current folder. They are printed out with timestamps.
sort sorts the lines based on timestamp (oldest on top).
head prints out the top lines, up to the last 3 lines.
cut removes the timestamps.
xargs runs rm for every selected file.

查找列出当前文件夹中的所有文件(非目录)。他们用时间戳印出来。根据时间戳排序(最老的在上面)。头部打印出最上面的几行,直到最后三行。删除时间戳。xargs为每个选定的文件运行rm。

For you to verify my solution:

供您验证我的解决方案:

(
touch -d "6 days ago" test_6_days_old
touch -d "7 days ago" test_7_days_old
touch -d "8 days ago" test_8_days_old
touch -d "9 days ago" test_9_days_old
touch -d "10 days ago" test_10_days_old
)

This creates 5 files with different timestamps in the current folder. Run this first and the code for deleting to test the code.

这将在当前文件夹中创建5个具有不同时间戳的文件。运行第一个和删除代码来测试代码。

#5


1  

Don't use ls -t as it is unsafe for filenames that may contain whitespaces or special glob characters.

不要使用ls -t,因为它对可能包含空格或特殊手套字符的文件名不安全。

You can do this using all gnu based utilities to delete all but 3 newest files in the current directory:

您可以使用所有基于gnu的实用工具来删除当前目录中除3个最新文件之外的所有文件:

find . -maxdepth 1 -type f -printf '%T@\t%p\0' |
sort -z -nrk1 |
tail -z -n +4 |
cut -z -f2- |
xargs -0 rm -f --

#6


0  

This uses find instead of ls with a Schwartzian transform.

它使用find而不是具有Schwartzian转换的ls。

find . -type f -printf '%T@\t%p\n' |
sort -t $'\t' -g |
tail -3 |
cut -d $'\t' -f 2-

find searches the files and decorates them with a time stamp and uses the tabulator to separate the two values. sort splits the input by the tabulator and performs a general numeric sort, which sorts floating point numbers correctly. tail should be obvious and cut undecorates.

查找文件并使用时间戳对其进行修饰,并使用tabulator分隔两个值。sort通过制表符分割输入并执行一个通用的数字排序,它正确地对浮点数进行排序。尾巴要明显,切得不雅观。

The problem with decorations in general is to find a suitable delimiter, which is not part of the input, the file names. This answer uses the NULL character.

装饰品的问题通常是找到一个合适的分隔符,它不是输入的一部分,也不是文件名。这个答案使用空字符。