如何从文件名中提取特定元素?

如何从文件名中提取特定元素?

我有一堆以下格式的文件:

2014-11-19.8.ext
2014-11-26.1.ext
2014-11-26.2.blah.ext
2014-11-26_3.ext
2014-11-26.4.stuff_here.ext
2014-12-03.1. could be anything.ext
2014-12-032b.ext
2014-11-26 613 adva.ext

我的目标是迭代整个文件列表,并从中获取日期格式YYYY-MM-DD并将其存储在变量中,YYYYMMDD以进行进一步处理(在我的例子中,它将被推入touch命令中)。

所以通常我会匹配这个正则表达式:(\d{4})-(\d{2})-(\d{2}).*

然后用来$1$2$3获取我想要的模式,但是我不确定如何在bash/中执行此操作zsh

如何在 shell 脚本中完成此操作?

答案1

使用参数扩展

$ touch 2014-11-19.8.ext 2014-11-26.1.ext
$ for f in *.ext; do d="${f:0:4}${f:5:2}${f:8:2}"; echo "$d"; done
20141119
20141126
  • ${f:0:4}表示从索引开始的4个字符0f是变量名
  • 替换echo "$d"为您的代码

答案2

要循环当前目录中的每个文件并将其文件名与所需模式进行比较,然后设置一个包含日期片段的变量

for f in *
do 
  [[ $f =~ ^([0-9][0-9][0-9][0-9])-([0-9][0-9])-([0-9][0-9])(.*) ]] && 
  yourvar="${BASH_REMATCH[1]}${BASH_REMATCH[2]}${BASH_REMATCH[3]}"
done

这使用bash[[使用正则表达式匹配的能力将日期片段放入 BASH_REMATCH 数组中。

答案3

您可以使用以下命令以交互方式完成此操作GNU sed

$ sed 's/^\([0-9]\{4\}\)-\([0-9]\{2\}\)-\([0-9]\{2\}.*\)/\1\2\3/g' stuff.txt

对于多个文件(如果在同一目录中并且目录中没有其他考虑的文件):

for file in *
do
    if [ -f "$file" ]
    then
          sed 's/^\([0-9]\{4\}\)-\([0-9]\{2\}\)-\([0-9]\{2\}\).*/\1\2\3/g' "$file"
    fi
done

答案4

如果您使用 GNU Coreutils,您会看到:

$ date --date=2014-11-13 +"%Y%m%d"
20141113

然而:

$ date --date=2014-11-130ABCJUNK +"%Y%m%d"
date: invalid date ‘2014-11-130ABCJUNK’

因此,任务要简单得多:提取每个YYYY-MM-DDetc文件名的前十个字符以获取日期本身,然后传递给date重新格式化。

但是,如果我们使用 GNU Coreutils,我们可以跳过该date命令,因为touch有完全相同的--date=STRING选项。

for file in * ; do
  date=${file%${file##??????????}} # chop all but first ten
  touch --date=$date -- "$file"
done

touch但是,当我们依赖 GNU Coreutils时,为什么要以 POSIX 可移植方式进行这十个字符的切割呢?

for file in * ; do
  date=${file:0:10}
  touch --date=$date -- "$file"
done

相关内容