我从wunderground.com和我的天气一天,然后削减数据用于gnuplot。我无法将第二列数据从数字缩写为月份缩写。只对第二栏感兴趣。
我想离开这个;
>2013 08 02 23 37 00 73.3
>2013 08 02 23 42 00 73.4
>2013 08 02 23 45 00 73.3
>2013 08 02 23 47 00 73.1
>2013 08 02 23 52 00 73.1
>2013 08 02 23 57 00 73.1
对此:
>2013 AUG 02 23 37 00 73.3
>2013 AUG 02 23 42 00 73.4
>2013 AUG 02 23 45 00 73.3
>2013 AUG 02 23 47 00 73.1
>2013 AUG 02 23 52 00 73.1
>2013 AUG 02 23 57 00 73.1
我正在尝试使用sed将数字更改为正确的月份,我会继续这样做。我只希望正确的sed表达式不是全部执行。这是我试图使用的命令。
sed -e 's/01/JAN/' -e 's/02/FEB/' -e 's/03/MAR/' -e 's/04/APR/' -e 's/05/MAY/' -e 's/06/JUN/' -e 's/07/JUL/' -e 's/08/AUG/' -e 's/09/SEP/' -e 's/10/OCT/' -e 's/11/NOV/' -e 's/12/DEC/'
我将如何解决这个问题。
答案 0 :(得分:2)
这可能适合你(GNU sed):
sed -nri 'G;s/$/01JAN02FEB03MAR04APR05MAY06JUN07JUL08AUG09SEP10OCT11NOV12DEC/;s/ (..)(.*)\1(...)/ \3\2/;P' file
这会在每行的末尾添加一个查找表,并用键替换该值。
答案 1 :(得分:1)
适用于此问题的解决方法(因为您的第一列非常容易预测),但不是一般性问题:
sed -E -e 's/^([0-9]{4}) 01/\1 JAN/' -e 's/^([0-9]{4}) 02/\1 FEB/' etc.
awk
有一个sub
函数,对于您在此处的许多选项而言可能会变得难以处理。
Perl脚本可能是最好的方法。
答案 2 :(得分:1)
我会使用awk
:
$ awk 'BEGIN{split("Jan Feb Mar Apr May Jun Jul Aug Sep Oct Nov Dec",a)} {$2=a[$2+0]}1' a
>2013 Aug 02 23 37 00 73.3
>2013 Aug 02 23 42 00 73.4
>2013 Aug 02 23 45 00 73.3
>2013 Aug 02 23 47 00 73.1
>2013 Aug 02 23 52 00 73.1
>2013 Aug 02 23 57 00 73.1
要使用新内容更新字段,只需重定向然后移动:
awk .... file > temp_file && mv temp_file file
我们所做的是为awk
提供一个包含月份名称的字符串列表。一旦我们将其转换为数组,a[1]
将是Jan,a[2]
2月,依此类推。那么这只是用a[2nd field]
替换第二个字段的问题。
BEGIN{split("Jan Feb Mar Apr May Jun Jul Aug Sep Oct Nov Dec",a)}
获取数据并插入a[]
数组。{$2=a[$2+0]}
将第二个字段设为a[2nd field]
。完成$2+0
以将08
转换为8
。1
评估为真,并awk
执行默认操作:{print $0}
。答案 3 :(得分:1)
使用gnu awk的函数strftime()和mktime()
awk '{$2=strftime("%b",mktime("2014 " $2 " 1 1 0 0"))}1' file
>2013 Aug 02 23 37 00 73.3
>2013 Aug 02 23 42 00 73.4
>2013 Aug 02 23 45 00 73.3
>2013 Aug 02 23 47 00 73.1
>2013 Aug 02 23 52 00 73.1
>2013 Aug 02 23 57 00 73.1
mktime("2014 " $2 " 1 1 0 0")
假冒纪元时间,将第2列用作月份strftime("%b",mktime("2014 " $2 " 1 1 0 0"))
将纪元转换回日期,%b
,导出缩写的月份名称(Jan,Feb等)当然,它更短。其次,您可以在strftime()中控制/调整格式以导出您喜欢的任何日期格式。
例如,如果更改为full month name %B
。您无需重写代码。
awk '{$2=strftime("%B",mktime("2014 " $2 " 1 1 0 0"))}1' file
答案 4 :(得分:1)
$ awk '{$2=substr("JanFebMarAprMayJunJulAugSepOctNovDec",(3*$2)-2,3)}1' file
>2013 Aug 02 23 37 00 73.3
>2013 Aug 02 23 42 00 73.4
>2013 Aug 02 23 45 00 73.3
>2013 Aug 02 23 47 00 73.1
>2013 Aug 02 23 52 00 73.1
>2013 Aug 02 23 57 00 73.1
因为它出现在评论中:
从月份编号映射到名称的惯用awk方式是:
number = (match("JanFebMarAprMayJunJulAugSepOctNovDec",<name>)+2)/3
以上就是这个的自然反转:
name = substr("JanFebMarAprMayJunJulAugSepOctNovDec",(3*<number>)-2,3)
与awk中的任何内容一样,有各种方法可以获得您想要的输出,但恕我直言,这里的对称性使它成为一个有吸引力的解决方案:
awk 'BEGIN{
months = "JanFebMarAprMayJunJulAugSepOctNovDec"
name = "Jul"
number = (match(months,name)+2)/3
print name " -> " number
name = substr(months,(3*number)-2,3)
print number " -> " name
}'
Jul -> 7
7 -> Jul
请注意,无论转换的方向是什么,脚本都会使用相同的定义,并且在两个方向上都是类似的数学计算。
当然这样做也没有错:
awk 'BEGIN{
split("Jan Feb Mar Apr May Jun Jul Aug Sep Oct Nov Dec",num2name)
for (number in num2name) {
name2num[num2name[number]] = number
}
name = "Jul"
number = name2num[name]
print name " -> " number
name = num2name[number]
print number " -> " name
}'
Jul -> 7
7 -> Jul
还有几行代码,nbd。