如何从Bash中的文件名中只提取一大块数字?

时间:2017-01-17 20:55:25

标签: bash awk sed grep

在另一个问题中,用户@Cyrus解释了how to extract the dates from a filename。我现在必须考虑文件名中可能有其他数字垃圾的文件。

我的一些文件有前缀。例如:

01 - Camera 03 - 20161231.mp4
02 - Camera 03 - 20161231.mp4
03 - Camera 03 - 20161231.mp4

他的原始答案(如下)显示了假设文件名没有这个垃圾的方法:

for i in *; do
  [[ $i =~ [0-9]{8}|[0-9]{4}-[0-9]{2}-[0-9]{2} ]]
  x="${BASH_REMATCH[0]//-/}"
  y="${x:0:4}"
  m="${x:4:2}"
  d="${x:6:2}"
  echo "$y $m $d"
done | sort -n

有没有办法提取符合某种模式的文件名块?例如:

yyyyMMdd
yyyyMMddHHmmss
yyyy-MM-dd HH-mm-ss

与其他问题一样,我的目标是从DATE部分获取值而忽略垃圾(前缀,非日期数字等):

输出:

2010 12 20
2016 01 01
2016 04 13
2017 01 11
2017 01 17 16 02 30

提前谢谢。

1 个答案:

答案 0 :(得分:1)

把它放在一个脚本中:

#!/bin/bash -ue

match_timestamp()
{
local 
local -r line="$1"

[[ "$line" =~ $TIMESTAMP_PATTERN ]] || return # Return if non-matching

# We have a match
echo "Match found"
echo "   Line received : $line"
echo "       Timestamp : "

YR="${BASH_REMATCH[2]}"
MO="${BASH_REMATCH[4]}"
DM="${BASH_REMATCH[6]}"
HH="${BASH_REMATCH[8]}"
MM="${BASH_REMATCH[10]}"
SS="${BASH_REMATCH[12]}"

if
  [[ "$YR" ]] && [[ "$MO" ]] && [[ "$DM" ]]
then
  # The date is available, we print it
  echo -n "  $YR-$MO-$DM"
  if
    [[ "$HH" ]] && [[ "$MM" ]]
  then
    # The time is available, we print it
    echo -n " $HH:$MM"
    if
      [[ "$SS" ]]
    then
      # Seconds are available, we print that too
      echo -n ":$SS"
    fi
  fi
  echo
fi

}

main()
{

# Constants declared here once, reused in other function (regex patterns)
local -r PYR="([12][0-9][0-9][0-9])"
local -r PMO="([01][0-9])"
local -r PDM="([1-9]|[0-3][0-9])"
local -r PHH="([0-2][0-9])?"
local -r PMM="([0-5][0-9])?"
local -r PSS="([0-5][0-9])?"

# Pattern for separator between fields (including no separator at all)
local -r SP="([^0-9a-zA-Z]*)"
# Pattern for anything but a digit
local -r NAD="[^0-9]"
# Big pattern that matches timestamps with flexibility
local -r TIMESTAMP_PATTERN="(^|$NAD)$PYR$SP$PMO$SP$PDM$SP$PHH$SP$PMM$SP$PSS($NAD|$)"

local line

if
  [[ -t 0 ]]
then
  for line in "$@"
  do
    match_timestamp "$line"
  done 
else
  while IFS= read -r line
  do
    match_timestamp "$line"
  done
fi
}

main "$@"

此脚本可以在标准输入上接收字符串(文件名或其他)(每行一个)或提供字符串作为参数;如果标准输入未连接到终端,则应用第一种模式,否则应用第二种模式。

根据建议,它只会匹配4位数年份,2位数月份,日期,小时,分钟和秒。但是,可以省略任何一天之后的任何内容,它仍然会与找到的部分匹配(使用较小的连接正则表达式生成的单个大正则表达式)。通过调整正则表达式可以增加灵活性。您可以使用或不使用分隔符(感谢分隔符正则表达式)。

模式不是防弹的(例如,25小时将被接受,2月30日将被接受),但出于基本目的,它应该是有用的。

看到结果有多好,这是我要保留的!