如何删除除最近创建的文件之外的所有具有模式的文件

如何删除除最近创建的文件之外的所有具有模式的文件

如何删除除最近创建的文件之外的所有具有模式的文件

ls -l
total 655748
-rw-r--r-- 1 jetty jetty 120579643 May 10 19:59 2023_05_10.jetty.log
-rw-r--r-- 1 jetty jetty 115205809 May 11 19:59 2023_05_11.jetty.log
-rw-r--r-- 1 jetty jetty 102921116 May 12 19:59 2023_05_12.jetty.log
-rw-r--r-- 1 jetty jetty  85266768 May 13 19:59 2023_05_13.jetty.log
-rw-r--r-- 1 jetty jetty  97032182 May 14 19:59 2023_05_14.jetty.log
-rw-r--r-- 1 jetty jetty 117095164 May 15 19:59 2023_05_15.jetty.log
-rw-r--r-- 1 jetty jetty  33339025 May 16 04:13 2023_05_16.jetty.log

答案1

假设你确实需要文件创建时间,你需要Ubuntu 20.10 或更高版本,因为之前 GNU coreutils 工具无法访问文件创建时间。

但在 20.10 及更新版本中,您可以使用:

find some/directory -type f -exec stat --format '%W' {} \; -printf "%p\0" |
  sort -zn |
  sed -z 's/^[0-9.]*\n//; $d' |
  xargs -r0 echo rm --
  • 整个管道使用空分隔数据,这是处理文件名最安全的方式
  • GNUfind无法访问 Linux 上的出生时间但是,所以我们使用它stat来打印出生时间,然后使用find它来打印文件名并用空字符来分隔它
  • 然后我们按数字对数据进行排序(基于创建时间)
  • 然后我们删除出生时间前缀,只留下文件名,并删除最后一行,即最新的文件
  • 然后我们使用xargs删除rm所有这些文件。上面的命令使用echo rm显示将要运行的命令 — 删除echo以实际运行rm并删除文件。

答案2

这个问题可以通过使用按最近修改的顺序列出文件的ls选项来解决。通过该选项,我们可以排除当前目录中可能存在的任何子目录。-t-p

经过我的测试,它看起来应该是这样的:

[11:55:08] /home/jaska/src/foo/> ls -tp 
baz.log  bar/  bar.log  foo.log  foo  barbaz

接下来我们需要使用grep来摆脱不需要的目录:

[11:55:16] /home/jaska/src/foo/> ls -tp | grep -v '/$'                          
baz.log
bar.log
foo.log
foo
barbaz

然后我们必须声明模式,再次使用grep

[11:55:28] /home/jaska/src/foo/> ls -tp | grep -v '/$' | grep \.log             
baz.log
bar.log
foo.log

因为它们已经处于正确的顺序,所以我们习惯tail从下往上删除一定量:

[11:55:21] /home/jaska/src/foo/> ls -tp | grep -v '/$' | grep \.log | tail -n +2
bar.log
foo.log

最后我们删除指定的文件:

[11:52:05] /home/jaska/src/foo/> ls -tp | grep -v '/$' | grep \.log | tail -n +2 | xargs -I {} rm -- {}
[12:01:59] /home/jaska/src/foo/> ll
total 4
drwxrwxr-x 2 jaska jaska 4096 May 16 11:53 bar/
-rw-rw-r-- 1 jaska jaska    0 May 16 11:48 barbaz
-rw-rw-r-- 1 jaska jaska    0 May 16 11:54 baz.log
-rw-rw-r-- 1 jaska jaska    0 May 16 11:50 foo

您可能会注意到,唯一剩下的 .log 文件未列在最新输出中,因为它是最近修改的。

回顾一下,要使用的完整命令是:

ls -tp | grep -v '/$' | grep \.log | tail -n +2 | xargs -I {} rm -- {}

您可能需要修改第二grep部分以适合某些日志文件,但从您提供给我们的列表来看,这应该足够了。

致谢及各部分的完整解释可在此处找到:https://stackoverflow.com/questions/25785/delete-all-but-the-most-recent-x-files-in-bash

答案3

注释 # 1

您在输出中实际看到的ls -l是文件的最后修改日期和不是创建日期。

find具有模式匹配(通配符)就像-name "*jetty.log"并且它已经-mtime修改了好几天了......所以,例如:

find . -mtime +0 -type f -name "*jetty.log"

查找 24 小时前修改过的匹配文件...1 代表 48 小时,依此类推。

并且它已经-mmin修改了几分钟...所以,例如:

find . -mmin +10 -type f -name "*jetty.log"

查找 10 分钟前修改的匹配文件。

并且它具有-delete删除匹配文件的操作...例如:

find . -mtime +9 -type f -name "*jetty.log" -delete

查找10天前修改过的匹配文件并删除它们。

您可以通过添加来限制搜索到当前文件夹的第一级,-maxdepth 1以防止在子目录中匹配文件。

笔记2

我注意到您的文件名以日期模式开头,例如2923_05_10......如果这是一致的并且您想要按这些日期匹配,那么您可以使用模式匹配,例如:

find . -maxdepth 1 -type f -name "2023_05_1[0-4].jetty.log"

匹配名称中2023_05_10带有 to 的文件。2023_05_14

由于文件名中的这些日期模式可以轻松解析为实际日期,因此您也可以按bash如下方式执行此操作,例如:

#!/bin/bash

days=5 # Set the number of days from now for a date to be considered as recent

for f in *.jetty.log
  do
    f1="${f%%.*}"
    f1="${f1//_/-}"
    fd="$(date -d "$f1" '+%s')"
    td="$(date -d "- $days days" '+%s')"
    [ -f "$f" ] && [ "$fd" -lt "$td" ] && echo rm -- "$f"
    done

匹配并打印名称中日期超过 5 天的文件...如果输出是您想要的,则删除echo并重新运行它以删除这些文件。

注释 # 3

如果您的意思实际上是文件的创建/出生日期,那么您可以这样做,bash例如:

#!/bin/bash

days=5 # Set the number of days from now for a date to be considered recent

for f in *.jetty.log
  do
    cd="$(stat -c '%w' "$f")"
    fcd="$(date -d "$cd" '+%s')"
    td="$(date -d "- $days days" '+%s')"
    [ -f "$f" ] && [ "$fcd" -lt "$td" ] && echo rm -- "$f"
    done

匹配并打印创建日期超过 5 天的文件...如果输出是您想要的,则删除echo并重新运行它以删除这些文件。

但是,这个需要较新的内核,因为stat旧内核不支持访问出生日期...请参阅这个答案以获得关于此问题的更多解释。

注释 # 4

使用补充缺少的系统工具功能的功能来简化您的生活bash...例如,此bash功能:

function rm_old {

lfcd=0
for f in *
  do
    if [ -f "$f" ]
      then
        fcd="$(stat -c '%w' "$f")"
        fcd="$(date -d "$fcd" '+%s')"
        if [ "$fcd" -gt "$lfcd" ]
          then
            todelete+=("${tokeep[@]}")
            tokeep=("$f")
            lfcd="$fcd"
           elif [ "$fcd" -eq "$lfcd" ]
             then
               tokeep+=("$f")
            else
              todelete+=("$f")
            fi
        fi
    done

echo "These files will be DELETED:"
printf '\e[4;31m%s\e[0m\n' "${todelete[@]}"
echo "This/These file(s) will be KEPT:"
printf '\e[4;32m%s\e[0m\n' "${tokeep[@]}"
read -p "Confirm Y(Yes)/N(No)" answer
case "$answer" in

  Yes|yes|YES|Y|y)
    [ "${#todelete[@]}" -gt 0 ] && rm -- "${todelete[@]}" || echo "Exiting ..."
    ;;
  *)
    echo "Aborting ..."
    ;;
  esac

unset answer
unset todelete
unset tokeep
unset fcd
unset lfcd

}

将仅保留当前工作目录中最后创建的文件并删除其余文件。

相关内容