解析日期和时间格式 - Bash

Posted

技术标签:

【中文标题】解析日期和时间格式 - Bash【英文标题】:Parsing date and time format - Bash 【发布时间】:2015-01-01 10:36:09 【问题描述】:

我有这样的日期和时间格式(年月日):

20141105 11:30:00

我需要将年、月、日、小时和分钟值分配给变量。

我可以像这样年复一年地做到这一点:

year=$(awk 'print $1' log.log | sed 's/^\(....\).*/\1/')
day=$(awk 'print $1' log.log | sed 's/^.*\(..\).*/\1/')  
hour=$(awk 'print $2' log.log | sed 's/^\(..\).*/\1/')  

我怎样才能做到这一点?

--

我需要日志文件的每一行:

20141105 11:30:00 /bla/text.1
20141105 11:35:00 /bla/text.2
20141105 11:40:00 /bla/text.3
.... 

我正在尝试逐行读取此日志文件并执行以下操作:

mkdir -p "/bla/backup/$year/$month/$day/$hour/$minute"
mv $file "/bla/backup/$year/$month/$day/$hour/$minute"

这是我不工作的代码:

#!/bin/bash
LOG=/var/log/LOG

while read line
do

year=$line:0:4
month=$line:4:2
day=$line:6:2
hour=$line:9:2
minute=$line:12:2
file=$(awk 'print $3')

if [ -f "$file" ]; then

printf -v path "%s/%s/%s/%s/%s" $year $month $day $hour $minute
mkdir -p "/bla/backup/$path"
mv $file "/bla/backup/$path"

fi
done < $LOG

【问题讨论】:

你的最终目标是什么,为什么要把它们放在变量中? 我需要创建这样的路径 -> /bla/2014/11/05/11/30/ 你从哪里得到日期? Parse Date in Bash的可能重复 【参考方案1】:

你根本不需要调用 awk 到日期,使用 bash 的子字符串操作

d="20141105 11:30:00"
yr=$d:0:4
mo=$d:4:2
dy=$d:6:2
hr=$d:9:2
mi=$d:12:2
printf -v dir "/bla/%s/%s/%s/%s/%s/\n" $yr $mo $dy $hr $mi
echo "$dir"
/bla/2014/11/05/11/30/

或者直接,不带所有变量。

printf -v dir "/bla/%s/%s/%s/%s/%s/\n" $d:0:4 $d:4:2 $d:6:2 $d:9:2 $d:12:2

鉴于您的日志文件:

while read -r date time file; do
    d="$date $time"
    printf -v dir "/bla/%s/%s/%s/%s/%s/\n" $d:0:4 $d:4:2 $d:6:2 $d:9:2 $d:12:2
    mkdir -p "$dir"
    mv "$file" "$dir"
done < filename

或者,假设您的文件名中没有空格或通配符:

sed -r 's#(....)(..)(..) (..):(..):.. (.*)#mv \6 /blah/\1/\2/\3/\4/\5#' | sh

【讨论】:

如何在我的日志文件的所有行中执行此操作? 编辑您的问题以显示您的日志文件示例。【参考方案2】:

date 命令也可以完成这项工作

#!/bin/bash
year=$(date  +'%Y' -d'20141105 11:30:00')
day=$(date  +'%d' -d'20141105 11:30:00')
month=$(date  +'%m' -d'20141105 11:30:00')
minutes=$(date  +'%M' -d'20141105 11:30:00')
echo  "$year---$day---$month---$minutes"

【讨论】:

【参考方案3】:

您只能使用一个awk

month=$(awk 'print substr($1,5,2)' log.log)
year=$(awk 'print substr($1,0,4)' log.log)
minute=$(awk 'print substr($2,4,2)' log.log)
etc

【讨论】:

【参考方案4】:

我猜你正在处理日志文件,它的每一行都以日期字符串开头。您可能已经编写了一个循环来处理每一行,在您的循环中,您可以这样做:

d="$(awk 'print $1,$2' <<<"$line")"
year=$(date -d"$d" +%Y)
month=$(date -d"$d" +%m)
day=$(date -d"$d" +%d)
min=$(date -d"$d" +%M)

【讨论】:

【参考方案5】:

不要重复自己。

d='20141105 11:30:00'
IFS=' ' read -r year month day min < <(date -d"$d" '+%Y %d %m %M')

echo "year: $year"
echo "month: $month"
echo "day: $day"
echo "min: $min"

诀窍是让date输出你想要的字段,用一个字符(这里是空格)分隔,把这个字符放在IFS中,然后让read为你做分割。像这样,您只执行一次date,并且只生成一个子shell。

如果日期来自文件log.log 的第一行,您可以将其分配给变量d

IFS= read -r d < log.log

【讨论】:

【参考方案6】:
eval "$( 
   echo '20141105 11:30:00' \
    | sed 'G;s/\(....\)\(..\)\(..\) \(..\):\(..\):\(..\) *\(.\)/Year=\1\7Month=\2\7Day=\3\7Hour=\4\7Min=\5\7Sec=\6/'
    )"

通过分配字符串进行评估。您可以通过将点替换为更具体的模式(例如 [0-5][0-9] 为 min 和 sec,...

posix 版本所以--posix 在 GNU sed 上

【讨论】:

【参考方案7】:

我写了一个函数,我通常将它剪切并粘贴到我的脚本文件中

function getdate()

  local a
  a=(`date "+%Y %m %d %H %M %S" | sed -e 's/ / /'`)
  year=$a[0]
  month=$a[1]
  day=$a[2]
  hour=$a[3]
  minute=$a[4]
  sec=$a[5]

在脚本文件中,单独一行

获取日期

echo "year=$year,month=$month,day=$day,hour=$hour,minute=$minute,second=$sec"

当然,您可以修改我提供的内容或使用上面的答案 [6]。 该函数不接受任何参数。

【讨论】:

以上是关于解析日期和时间格式 - Bash的主要内容,如果未能解决你的问题,请参考以下文章

sh Bash - 日期模块 - 作为时间戳计数器的不同格式,函数和循环,用作父脚本的模块。

sh Bash - 日期模块 - 作为时间戳计数器的不同格式,函数和循环,用作父脚本的模块。

Excel的日期格式约定与解析

在字符串中解析和格式化日期

如何使用 Jackson 和 java.time 解析不同的 ISO 日期/时间格式?

Bash:格式化日期[重复]