测试文件是否在文件名中的日期之后被修改

测试文件是否在文件名中的日期之后被修改

我有一个文件名中带有 的文件YYYYMMDD,例如

file-name-20151002.txt

我想确定是否文件于2015年10月2日后修改。

笔记:

  • 我可以通过查看 的输出来做到这一点ls,但我知道解析 的输出ls是一个坏主意。
  • 我不需要寻找全部日期在特定日期之后的文件,只需测试一次指定一个文件。
  • 我不担心文件在创建后的同一天被修改。也就是说,我只想知道20151002名称中的这个文件是否在2015年10月3日或更晚的时间被修改过。
  • 我使用的是 MacO 10.9.5。

答案1

以下脚本将检查命令行上指定的所有文件的日期:

它需要 GNU 版本的seddatestat

$ cat check-dates.sh 
#! /bin/bash

for f in "$@" ; do
  # get date portion of filename
  fdate=$(basename "$f" .txt | sed -re 's/^.*(2015)/\1/')

  # convert it to seconds since epoch + 1 day
  fsecs=$(echo $(date +%s -d "$fdate") + 86400 | bc )

  # get modified timestamp of file in secs since epoch
  ftimestamp=$(stat -c %Y "$f")

  [ "$ftimestamp" -gt "$fsecs" ] && echo "$f has been modified after $fdate"
done

$ ./check-dates.sh file-name-20151002.txt 
file-name-20151002.txt has been modified after 20151002
$ ls -l file-name-20151002.txt 
-rw-rw-r-- 1 cas cas 0 Oct 26 19:21 file-name-20151002.txt

这是一个未经测试的版本,但如果我正确阅读了在线手册页,应该可以在 Mac(以及 FreeBSD 等)上运行:

#! /bin/bash

for f in "$@" ; do
  # get date portion of filename
  fdate=$(basename "$f" .txt | sed -e 's/^.*\(2015\)/\1/')

  # convert it to seconds since epoch + 1 day
  fsecs=$(echo $(date -j -f %Y%m%d "$fdate" +%s) + 86400 | bc )

  # get modified timestamp of file in secs since epoch
  ftimestamp=$(stat -f %m "$f")

  [ "$ftimestamp" -gt "$fsecs" ] && echo "$f has been modified after $fdate"
done

答案2

以下是一些可能的方法:

  • OSX stat:

    newer () {
    tstamp=${1:${#1}-12:8}
    mtime=$(stat -f "%Sm" -t "%Y%m%d" "$1")
    [[ ${mtime} -le ${tstamp} ]] && printf '%s\n' "$1 : NO: mtime is ${mtime}" || printf '%s\n' "$1 : YES: mtime is ${mtime}"
    }
    
  • GNU date:

    newer () {
    tstamp=${1:${#1}-12:8}
    mtime=$(date '+%Y%m%d' -r "$1")
    [[ ${mtime} -le ${tstamp} ]] && printf '%s\n' "$1 : NO: mtime is ${mtime}" || printf '%s\n' "$1 : YES: mtime is ${mtime}"
    }
    
  • zsh仅有的:

    zmodload zsh/stat
    newer () {
    tstamp=${1:${#1}-12:8}
    mtime=$(zstat -F '%Y%m%d' +mtime -- $1)
    [[ ${mtime} -le ${tstamp} ]] && printf '%s\n' "$1 : NO: mtime is ${mtime}" || printf '%s\n' "$1 : YES: mtime is ${mtime}"
    }
    

用法:

较新的文件

输出示例:

file-name-20150909.txt : YES: mtime is 20151026

或者

file-name-20151126.txt : NO: mtime is 20151026

答案3

使用 bash 和statexpr获取数字形式的日期并进行比较:

#!/bin/bash
for file
do  moddate=$(stat -f %m -t %F "$file") # MacOS stat
    moddate=${moddate//-/} # 20151026
    if filedate=$(expr "$file" : '.*-\([0-9]*\).txt')
    then  if [ $moddate -gt $filedate ]
          then echo "$file: modified $moddate"
          fi
    fi
done

这是我之前针对 Linux 的回答。

#!/bin/bash
for file
do  moddate=$(stat -c %y "$file")
    moddate=${moddate%% *} # 2015-10-26
    moddate=${moddate//-/} # 20151026
    if [[ "$file" =~ ([0-9]{8}).txt$ ]]
    then  if [[ $moddate > ${BASH_REMATCH[1]} ]]
          then echo "$file: modified $moddate"
          fi
    fi
done

bash=~正则表达式运算符将文件名的 8 位数字捕获到 bash 数组 BASH_REMATCH 中。[[ ]]比较字符串,尽管您只是将它们作为数字进行比较,而不是在[ -gt ].

答案4

另一种zsh方法:

zmodload zsh/stat # best in ~/.zshrc or
zmodload -F zsh/stat +b:zstat # to avoid overriding an eventual
                              # system stat command.
setopt extendedglob # best in ~/.zshrc

ls -ld -- **/*[0-9](#c8)*(De@'zstat -F %Y%m%d -A m +mtime $REPLY &&
  [[ ${(SM)${REPLY:t}#[0-9](#c8)} != $m ]]'@)

将报告名称中看起来像时间戳但与上次修改时间不对应的文件。

zsh有大量类似的运算符来操作全局变量和变量。快速(并且通常可靠)完成任何工作非常方便,但很难完全理解所有工作,并且通常会产生我们通常所说的结果只写代码(难以辨认的代码的委婉说法,但也意味着您在命令提示符下编写单次使用时不需要阅读它)

快速浏览一下:

  • **/pattern(qualifier):带有 glob 限定符的递归 glob。
  • [0-9](#c8)匹配8位数字。这就是 zsh Extendedglob 等价于kshs的内容{8}([0-9])
  • D: 包含隐藏文件
  • e@...@: 这评估glob 限定符运行一些文本来进一步限定文件。传入的文件路径$REPLY
  • zstat...检索数组中格式为 YYYYMMDD 的 mtime $m
  • ${REPLY:t}: 扩展到t文件的 tail (基本名称)。
  • ${(SM)something#pattern}。提取匹配的部分图案某物。那些SSubstring 搜索)和M(扩展为中号附着部分)被称为参数扩展标志

相关内容