解析日期和时间格式 - Bash

3
我有一个日期和时间格式,如下(年月日):
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

你的最终目标是什么?为什么要将它们放入变量中? - user3442743
我需要创建这样的路径 -> /bla/2014/11/05/11/30/ - onur
你从哪里获取日期的? - user3442743
可能是在Bash中解析日期的重复问题。 - Dave Jarvis
7个回答

3

您无需调用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

我怎样才能处理我的日志文件中的所有行? - onur
编辑您的问题以显示日志文件示例。 - glenn jackman

1
我写了一个函数,通常会将其复制并粘贴到我的脚本文件中。
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]}
}

在脚本文件中,单独一行写上:
getdate echo "year=$year,month=$month,day=$day,hour=$hour,minute=$minute,second=$sec"
当然,你可以修改我提供的内容或使用上面的第6个答案。 该函数不需要任何参数。

1

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"

1
您只能使用一个 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

1

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

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)

1

不要重复自己。

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

1
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] 表示分钟和秒)来检查内容...
在GNU sed上使用--posix以使用POSIX版本。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接