【问题标题】:AWK - change the date of the secondAWK - 更改第二个日期
【发布时间】:2012-11-03 10:41:22
【问题描述】:

我有一个文件:

pablo tty8 Thu Nov 1 12:51:21 2012 still logged in 
(unknown tty8 Thu Nov 1 12:50:57 2012 - Thu Nov 1 12:51:21 2012 (00:00) 
pablo tty2 Thu Nov 1 12:50:39 2012 still logged in 
pablo tty7 Thu Nov 1 12:49:45 2012 - Thu Nov 1 12:50:56 2012 (00:01) 
(unknown tty7 Thu Nov 1 12:34:32 2012 - Thu Nov 1 12:49:45 2012 (00:15)

我想替换上述日期的文件一秒钟。我要打印:

pablo tty8 1351770681 still logged in 
(unknown tty8 1351770657 - 1351770681 (00:00) 
pablo tty2 1351770639 still logged in 
pablo tty7 1351770585 - 1351770656 (00:01) 
(unknown tty7 1351769672 - 1351770585 (00:15)

我试过这个命令:

gawk --posix 'function my()
{"date -d \047"$0"\047 +%s" | getline b; 
gsub( /[A-Za-z]{3} [A-Za-z]{3} [0-9] ([0-9]{2}:){2}[0-9]{2} [0-9]{4}/,b ); print}
{ my() }' file

上面的命令不起作用:

$ gawk --posix 'function my()
> {"date -d \047"$0"\047 +%s" | getline b; 
> gsub( /[A-Za-z]{3} [A-Za-z]{3} [0-9] ([0-9]{2}:){2}[0-9]{2} [0-9]{4}/,b ); print}
> { my() }' ta
date: błędna data: `pablo tty8 Thu Nov 1 12:51:21 2012 still logged in '
pablo tty8  still logged in 
(unknown tty8 1351897200 - 1351897200 (00:00) 
date: błędna data: `pablo tty2 Thu Nov 1 12:50:39 2012 still logged in '
pablo tty2 1351897200 still logged in 
date: błędna data: `pablo tty7 Thu Nov 1 12:49:45 2012 - Thu Nov 1 12:50:56 2012 (00:01) '
pablo tty7 1351897200 - 1351897200 (00:01) 
(unknown tty7 1351897200 - 1351897200 (00:15)

如何改进上述命令?

感谢您的帮助。

【问题讨论】:

标签: awk gsub


【解决方案1】:

如果你安装了vim,试试这个命令:

:%s/\v\w+\s\w+\s\d+\s\d+:\d+:\d+\s\d+/\=system('date +%s -d"'.submatch(0).'" | tr -d "\n"')/g

这个想法很简单。 vim 可以很快。

【讨论】:

    【解决方案2】:

    这是使用GNU awk 的一种方式。运行如下:

    awk -f script.awk file.txt
    

    script.awk的内容:

    {
        line = ($0 ~ /still logged in/) ? "still logged in" : "-" OFS getstamp(10) OFS $NF
        print $1, $2, getstamp(4), line
    } 
    
    function getstamp(i) {
    
        split($(i + 2), T, ":")
    
        Y = $(i + 3)
        M = convert($i)
        D = $(i + 1)
    
        hrs = T[1] + 9
        min = T[2]
        sec = T[3]
    
        return(mktime(sprintf("%d %d %d %d %d %d", Y, M, D, hrs, min, sec)))
    }
    
    function convert(month) {
    
        return(((index("JanFebMarAprMayJunJulAugSepOctNovDec", month) - 1) / 3) + 1)
    }
    

    结果:

    pablo tty8 1351770681 still logged in
    (unknown tty8 1351770657 - 1351770681 (00:00)
    pablo tty2 1351770639 still logged in
    pablo tty7 1351770585 - 1351770656 (00:01)
    (unknown tty7 1351769672 - 1351770585 (00:15)
    

    【讨论】:

    • 感谢您提供好的解决方案。我只是想知道你能不能按照我的方式去做?
    • @Tedee12345:我已经更新了脚本以产生您需要的确切结果。我不确定为什么需要将小时数调整为 9,但它会为您提供所需的结果。另外,我会避免像您尝试做的那样致电dateawk 有一些很好的内置时间功能,date 是不必要的。 HTH。
    • 谢谢伙计!很高兴我能帮上忙。干杯。
    【解决方案3】:

    这是在awk 中使用date 的解决方案(可能仅限gawk

    awk --posix '
    {
      while(match($0,/([[:alpha:]]{3} ){2}[^[:alpha:]]+[0-9]{4}/)){
        date_str=substr($0, RSTART, RLENGTH)
        "date -d \""date_str"\" +%s" | getline date_sec
        sub(date_str,date_sec,$0)
      }
      print
    }
    ' $1
    

    输出:

    pablo tty8 1351745481 still logged in 
    (unknown tty8 1351745457 - 1351745457 (00:00) 
    pablo tty2 1351745439 still logged in 
    pablo tty7 1351745385 - 1351745456 (00:01) 
    (unknown tty7 1351744472 - 1351744472 (00:15)
    

    注意事项:

    1. match-substr组合用于提取包含日期的子串。
    2. 使用date将日期子字符串转换为秒格式(+%s)并将秒分配给date_sec
    3. 用第二种格式的日期替换字符串格式的日期。
    4. 迭代直到找不到匹配项(如果没有找到匹配项,match 返回 0,从而终止 while 循环)
    5. 区间表达式只允许在gawk 中使用--re-interval--posix 选项

    【讨论】:

    • 它不是 gawk-only,它可以在任何 POSIX awk 和任何其他支持 RE 间隔的 awk 中工作。您添加了 --posix ,因此 gawk 可以正确处理像 {3} 这样的 RE 间隔,但仅供参考,这是较新 gawk 版本中的默认行为,在较旧的版本中,使用 --re-interval 比使用 --posix 更好,因为后者会禁用所有其他 GNU awk 扩展,如 gensub() 和时间函数。最后,您不需要使用 gawk 调用外部“日期”命令,因为它有自己的内置时间函数。
    猜你喜欢
    • 2019-07-25
    • 1970-01-01
    • 2012-09-19
    • 1970-01-01
    • 1970-01-01
    • 2023-03-29
    • 1970-01-01
    • 2017-05-13
    • 1970-01-01
    相关资源
    最近更新 更多