String Bash脚本,用于选择具有最新日期且不带子字符串的文件名

String Bash脚本,用于选择具有最新日期且不带子字符串的文件名,string,bash,shell,ubuntu,filenames,String,Bash,Shell,Ubuntu,Filenames,如果目录/dat包含文件名为 base-2020-01-01.dat base-2020-01-01-incremental-2020-01-02.dat base-2020-01-01-incremental-2020-01-03.dat base-2020-01-03.dat base-2020-01-03-incremental-2020-01-04.dat base-2020-01-03-incremental-2020-01-05.dat 我们如何编写一个选择 不带-incremen

如果目录/dat包含文件名为

base-2020-01-01.dat
base-2020-01-01-incremental-2020-01-02.dat
base-2020-01-01-incremental-2020-01-03.dat
base-2020-01-03.dat
base-2020-01-03-incremental-2020-01-04.dat
base-2020-01-03-incremental-2020-01-05.dat
我们如何编写一个选择

不带-incremental-*子字符串的base-*.dat文件名,其文件名中的日期是最近的日期。 此文件名中的日期字符串 在本例中,我们希望选择base-2020-01-03.dat和2020-01-03


如果不同的文件命名约定使解析更容易,那就更好了

出于偏执的考虑,使用GNU工具允许使用空分隔符,这样带有文字换行符的文件名就不会在逻辑中引入垃圾,或者至少不会做任何不正常的事情,除非最后排序:

printf '%s\0' /data/base-*.dat |
  sort --zero-terminated |
  grep --null -v incremental |
  tail --zero-terminated -n 1
如果您不在GNU平台上,您没有所有以-zero结尾或-null选项,请将printf格式字符串中的\0更改为\n,并删除上述选项。

使用现代GNU工具:使用find、grep-p和bash进行错误处理

read file < <(
  find /data -maxdepth 1 -name 'base*.dat' ! -name '*incremental*' \
    -printf '%f\n' | sort -nr | head -n1
)
set -e
echo "${file:?$(tput setaf 1)no match$(tput sgr0;exit 1)}"
date=$(grep -oP "\d{4}-\d{2}-\d{2}" <<< "$file")
echo "$date"

以下是另一种可能的解决方案:

date=$(find /dat -name 'base-[0-9][0-9][0-9][0-9]-[0-9][0-9]-[0-9][0-9].dat' -printf '%f\n' | sort -r | grep -o '[0-9][^.]*' -m1)

[ -n "$date" ] && echo "$date base-$date.dat"
“查找”输出名为base-yyy-MM-DD.dat的所有文件的列表 sort-r首先使用最新日期对列表进行排序 grep-o提取日期部分,使用-m1在第一行停止 使用纯bash扩展globs和参数扩展,无需外部程序:

#!/usr/bin/env bash
shopt -s extglob
declare -a files=(base-!(*incremental*).dat)
echo "Non-incremental files: ${files[*]}"
justdate="${files[-1]#base-}"
justdate="${justdate%.dat}"
echo "Most recent file: ${files[-1]} from $justdate"
用法:

$ ls
base-2020-06-29.dat  base-2020-06-30-incremental-2020-07-01.dat  base-2020-07-01.dat  demo.sh
$ bash demo.sh
Non-incremental files: base-2020-06-29.dat base-2020-07-01.dat
Most recent file: base-2020-07-01.dat from 2020-07-01

假设YYYY-MM-DD,命名约定是绝对完美的;只需一个简单的ASCII排序就可以将事情按正确的顺序排列,因此标准UNIX工具排序,grep,不管是head还是tail都可以做得很好。一件更简单的事情是将完整备份保存在一个目录/dat/full中,将增量备份保存在另一个目录/dat/inc中。然后您可以这样找到它们:latest_full=$ls/dat/full | tail-1查找数据-键入f-name'??-[0-9][0-9][0-9]-[0-9][0-9]-[0-9][0-9].dat-printf“%f\n”和GNU find?,不是一个解决方案,只是一个开始[[$file=~.[[:digit:]]{4}-[:digit:]]{2}-[:digit:]{2}.]&&printf“%s\n'${BASH_REMATCH[@]}没有grep?IINM您只是选择find输出的第一个文件。find不确保任何特定的订购。根据文件名,您不能假定找到的第一个文件是最新的。我的答案是?不,文件名扩展会自动对结果排序。我尝试了“extglob”,这不是简单的方法。我认为“发现”更自然。。。而且觉得“查找”更可靠,不是要求的格式:文件+日期。很好的建议,但在现实生活中从未见过使用newline的文件,因为Linux计算my 2已经有近20年了cents@GillesQuenot,我见过使用随机内存中的名称创建的文件,缓冲区溢出将其转储到错误的位置。这就是我反复提到的现实世界中数据丢失问题的原因。做好防御性编程意味着准备好所有可能的输入,即使是不太可能的输入。此外,如果我是红色团队的成员,试图找出如何使用系统先前存在的cron作业——可能是为了让它们管理错误的东西,从而删除一些日志以覆盖我的跟踪——那么最好相信我会考虑它们如何使用换行符管理文件名。
$ ls
base-2020-06-29.dat  base-2020-06-30-incremental-2020-07-01.dat  base-2020-07-01.dat  demo.sh
$ bash demo.sh
Non-incremental files: base-2020-06-29.dat base-2020-07-01.dat
Most recent file: base-2020-07-01.dat from 2020-07-01