我在bash中有这种日期时间格式的数据:
28/11/13 06:20:05
(dd / mm / yy hh:mm:ss)
我需要重新格式化:
2013-11-28 06:20:05
(MySQL日期时间格式)
我正在使用以下正则表达式:
regex='([0-9][0-9])/([0-9][0-9])/([0-9][0-9])\s([0-9][0-9]/:[0-9][0-9]:[0-9][0-9])'
if [[$line=~$regex]]
then
$line='20$3-$2-$1 $4';
fi
这会产生错误:
./filename: line 10: [[09:34:38=~([0-9][0-9])/([0-9][0-9])/([0-9][0-9])\s([0-9][0-9]/:[0-9][0-9]:[0-9][0-9])]]: No such file or directory
更新:
我想“逐行”读取此文件,解析它并在mysql数据库中插入数据:
'filenameX':
27/11/13 12:20:05 9984 2885 260 54 288 94 696 1852 32 88 27 7 154
27/11/13 13:20:05 9978 2886 262 54 287 93 696 1854 32 88 27 7 154
27/11/13 14:20:05 9955 2875 262 54 287 93 696 1860 32 88 27 7 154
27/11/13 15:20:04 9921 2874 261 54 284 93 692 1868 32 88 27 7 154
27/11/13 16:20:09 9896 2864 260 54 283 92 689 1880 32 88 27 7 154
27/11/13 17:20:05 9858 2858 258 54 279 92 683 1888 32 88 27 7 154
27/11/13 18:20:04 9849 2853 258 54 279 92 683 1891 32 88 27 7 154
27/11/13 19:20:04 9836 2850 257 54 279 93 683 1891 32 88 27 7 154
27/11/13 20:20:05 9826 2845 257 54 279 93 683 1892 32 88 27 7 154
27/11/13 21:20:05 9820 2847 257 54 278 93 682 1892 32 88 27 7 154
27/11/13 22:20:04 9810 2844 257 54 277 93 681 1892 32 88 27 7 154
27/11/13 23:20:04 9807 2843 257 54 276 93 680 1892 32 88 27 7 154
28/11/13 00:20:05 9809 2843 257 54 276 93 680 1747 29 87 17 6 139
28/11/13 01:20:04 9809 2842 257 54 276 93 680 1747 29 87 17 6 139
28/11/13 02:20:05 9809 2843 256 54 276 93 679 1747 29 87 17 6 139
28/11/13 03:20:04 9808 2842 256 54 276 93 679 1747 29 87 17 6 139
28/11/13 04:20:05 9808 2842 256 54 276 93 679 1747 29 87 17 6 139
28/11/13 05:20:39 9807 2842 256 54 276 93 679 1747 29 87 17 6 139
28/11/13 06:20:05 9804 2840 256 54 276 93 679 1747 29 87 17 6 139
脚本:
#!/bin/bash
echo "Start!"
while IFS=' ' read -ra ADDR;
do
for line in $(cat results)
do
regex='([0-9][0-9])/([0-9][0-9])/([0-9][0-9]) ([0-9][0-9]:[0-9][0-9]:[0-9]$
if [[ $line =~ $regex ]]; then
$line="20${BASH_REMATCH[3]}-${BASH_REMATCH[2]}-${BASH_REMATCH[1]} ${BASH_REMATCH[4]}"
fi
echo "insert into table(time, total, caracas, anzoategui) values('$line', '$line', '$line', '$line', '$line');"
done | mysql -user -password database;
done < filenameX
结果:
时间|总计|加拉加斯| anzoategui |
00:00:00 | 9 | 9 | 9 |
2027-11-13 00:00:00 | 15 | 15 | 15 |
答案 0 :(得分:2)
注意:此答案是基于在OP中修复以bash为重点的方法而被接受的。对于更简单的基于awk
的解决方案,请参阅此答案的最后一部分。
尝试以下方法:
line='28/11/13 06:20:05' # sample input
regex='([0-9][0-9])/([0-9][0-9])/([0-9][0-9]) ([0-9][0-9]:[0-9][0-9]:[0-9][0-9])'
if [[ $line =~ $regex ]]; then
line="20${BASH_REMATCH[3]}-${BASH_REMATCH[2]}-${BASH_REMATCH[1]} ${BASH_REMATCH[4]}"
fi
echo "$line" # -> '2013-11-28 06:20:05'
至于为什么你的代码不起作用:
[[
右侧和]]
左侧至少需要一个空格。\s
在bash正则表达式中是否有效取决于平台(Linux:是; OSX:否),因此单个文字空间是更安全的选择。$line = ...
) - 当将分配给变量时,永远不要在变量名前加上$
。$1
,...):要在bash正则表达式中引用捕获组(子表达式),您必须使用特殊的${BASH_REMATCH[@]}
数组变量; ${BASH_REMATCH[0]}
包含匹配的整个字符串,${BASH_REMATCH[1]}
包含第一个捕获组匹配的内容,依此类推;相比之下,$1
,$2
,...是指传递给shell脚本或函数的第1个,第2个......参数。更新,以解决OP的更新问题:
我认为以下是你想要的:
# Read input file and store each col. value in separate variables.
while read -r f1 f2 f3 f4 f5 f6 f7 f8 f9 f10 f11 f12 f13 f14 f15; do
# Concatenate the first 2 cols. to form a date + time string.
dt="$f1 $f2"
# Parse and reformat the date + time string.
regex='([0-9][0-9])/([0-9][0-9])/([0-9][0-9]) ([0-9][0-9]:[0-9][0-9]:[0-9][0-9])'
if [[ "$dt" =~ $regex ]]; then
dt="20${BASH_REMATCH[3]}-${BASH_REMATCH[2]}-${BASH_REMATCH[1]} ${BASH_REMATCH[4]}"
fi
# Echo the SQL command; all of them are piped into a `mysql` command
# at the end of the loop.
# !! Fill the $f<n> variables in as needed - I don't know which ones you need.
# !! Make sure the number column name matches the number of values.
# !! Your original code had 4 column names, but 5 values, causing an error.
echo "insert into table(time, total, caracas, anzoategui) values('$dt', '$f3', '$f4', '$f5');"
done < filenameX | mysql -user -password database
事后补充:上述解决方案基于对OP代码的改进;下面是一个简化的解决方案,它是一个基于awk
的单行程序(为了便于阅读而分布在多行中 - 对于基于awk的日期重新格式化的@twalberg,提示:)
awk -v sq=\' '{
split($1, tkns, "/");
dt=sprintf("20%s-%s-%s", tkns[3], tkns[2], tkns[1]);
printf "insert into table(time,total,caracas,anzoategui) values(%s,%s,%s,%s);",
sq dt " " $2 sq, sq $3 sq, sq $4 sq, sq $5 sq
}' filenameX | mysql -user -password database
注意:要简化awk
程序中的引用,可以通过变量sq
(-v sq=\'
)传入单引号。
答案 1 :(得分:1)
Perl在这里很方便。
dt="28/11/13 06:20:05"
perl -MTime::Piece -E "say Time::Piece->strptime('$dt', '%d/%m/%y %T')->strftime('%Y-%m-%d %T')"
2013-11-28 06:20:05
答案 2 :(得分:1)
这样做没有任何过于复杂的正则表达式调用:
echo "28/11/13 06:20:05" | awk -F'[/ ]' \
'{printf "20%s-%s-%s %s\n", $3, $2, $1, $4}'
或者,正如@fedorqui在评论中所建议的那样,如果时间戳的来源为date
,您可以为其提供所需的格式选项...
答案 3 :(得分:0)
BASH中必须使用空格,因此请使用:
[[ "$line" =~ $regex ]] && echo "${line//\//-}"
此外,您无法在BASH中使用\s
,因此请使用此正则表达式:
regex='([0-9][0-9])/([0-9][0-9])/([0-9][0-9]) ([0-9][0-9]:[0-9][0-9]:[0-9][0-9])'
答案 4 :(得分:0)
感谢所有上述示例。
未附加“ T”
$line='"2020-11-26 10:20:01.000000","the size of the table is 3.5" (inches)","2020-12-11 10:20:02"'
$echo "$line" | sed -r 's#(\d{4}-\d{2}-\d{2}) (\d{2}:\d{2}:\d{2})#\2T\1#g'
"2020-11-26 10:20:01.000000","the size of the table is 3.5" (inches)","2020-12-11 10:20:02"
“ T”仅附加在第一列的中间,而不附加在该行中任何具有日期格式的列中
$awk '/[0-9]{4}-(0[1-9]|1[0-2])-(0[1-9]|[1-2][0-9]|3[0-1]) (2[0-3]|[01][0-9]):[0-5][0-9]*/{print}' test_file |sed -e 's/\s/\T/'
"2020-11-26T10:20:01.000000","the size of the table is 3.5" (inches)","2020-12-11 10:20:02"
上面带有分组的示例
$ line='"2020-11-26 10:20:01.000000","the size of the table is 3.5" (inches)","2020-12-11 10:20:02"'
$ regex='([0-9][0-9])-([0-9][0-9])-([0-9][0-9]) ([0-9][0-9]:[0-9][0-9]:[0-9][0-9])'
$ if [[ $line =~ $regex ]]; then line="20${BASH_REMATCH[3]}-${BASH_REMATCH[2]}-${BASH_REMATCH[1]}T${BASH_REMATCH[4]}"; fi
$ echo "$line"
2026-11-20T10:20:01
#......的意图是在具有数百万条记录的巨大csv文件中的所有字段的日期和时间(同一字段)之间添加“ T”,而不仅仅是第一列,且所有日期格式都为YYYY-MM-DD HH24:MI:SS