AskOverflow.Dev

AskOverflow.Dev Logo AskOverflow.Dev Logo

AskOverflow.Dev Navigation

  • 主页
  • 系统&网络
  • Ubuntu
  • Unix
  • DBA
  • Computer
  • Coding
  • LangChain

Mobile menu

Close
  • 主页
  • 系统&网络
    • 最新
    • 热门
    • 标签
  • Ubuntu
    • 最新
    • 热门
    • 标签
  • Unix
    • 最新
    • 标签
  • DBA
    • 最新
    • 标签
  • Computer
    • 最新
    • 标签
  • Coding
    • 最新
    • 标签
主页 / ubuntu / 问题 / 661332
Accepted
steve
steve
Asked: 2015-08-15 02:04:44 +0800 CST2015-08-15 02:04:44 +0800 CST 2015-08-15 02:04:44 +0800 CST

重新格式化表格

  • 772

我有以下类型的表:

ID   date     DailyFlow
a 1972-01-01 17.0265761797993
b 1972-01-02 17.200476457399
c 1972-01-03 17.2926436045271
d 1972-01-04 17.3900277599829
e 1972-01-05 17.5987080931028
f 1972-01-06 17.6334881486229
g 1972-01-07 17.7030482596626
...

我想将它们重新格式化如下:

YYYY    DDD sim
1972    1   17.0265761797993
1972    2   17.200476457399
1972    3   17.2926436045271
1972    4   17.3900277599829
1972    5   17.5987080931028
1972    6   17.6334881486229
1972    7   17.7030482596626
1972    8   17.7204382874227

第一行包含在表中。这些文件是带有“制表符”分隔符的纯文本 (*.txt)。ID 列是一个虚拟列,我想去掉它!在我想要的输出中,DDD 列中的数字 (1,2,3,...) 应与相应年份的日期相符。

有没有人知道如何做到这一点(使用 bash)?谢谢!

bash
  • 4 4 个回答
  • 263 Views

4 个回答

  • Voted
  1. kos
    2015-08-15T03:01:20+08:002015-08-15T03:01:20+08:00

    这本来是 的工作awk,但第二列中的替换将需要gensub,因此gawk默认情况下未安装,因此我最终得到了一个sed解决方案:

    sed -i.bak 's/[^\t]*\t\([^-]*\)-[0-9][0-9]-[0-9]\([0-9]\)[^\t]*\t\([^\t]*\)/\1\t\2\t\3/' infile
    

    或者,使用 ERE 缩短(感谢 user1598390):

    sed -E -i.bak 's/.*([0-9]{4})-[0-9]{2}-([0-9]{2})(.*)/\1\t\2\3/' infile
    
    • -i.bak:原地处理文件,将原文件备份到infile.bak

    sed命令分解:

    • s: 断言执行替换;
    • /: 开始模式
    • [^\t]*: 匹配任意数量的任意字符 not \t;
    • \t: 匹配一个\t字符
    • \(: 启动第一个捕获组
    • [^-]*: 匹配任意数量的任意字符 not -;
    • \): 停止第一个捕获组
    • -: 匹配一个-字符
    • [0-9]: 匹配任何数字
    • [0-9]: 匹配任何数字
    • -: 匹配一个-字符
    • [0-9]: 匹配任何数字
    • \(: 启动第二个捕获组
    • [0-9]: 匹配任何数字
    • \): 停止第二个捕获组
    • [^\t]*: 匹配任意数量的任意字符 not \t;
    • \t: 匹配一个\t字符
    • \(: 启动第三个捕获组
    • [^\t]*: 匹配任意数量的任意字符 not \t;
    • \): 停止第三个捕获组
    • /: 停止模式/开始替换字符串
    • \1: 反向引用替换为第一个捕获组
    • \2: 反向引用替换为第二个捕获组
    • \3: 反向引用替换为第三个捕获组
    • /: 停止替换字符串/启动修饰符

    示例文件的输出:

    user@debian ~/tmp % cat infile 
    a   1972-01-01  17.0265761797993
    b   1972-01-02  17.200476457399
    c   1972-01-03  17.2926436045271
    d   1972-01-04  17.3900277599829
    e   1972-01-05  17.5987080931028
    f   1972-01-06  17.6334881486229
    g   1972-01-07  17.7030482596626
    user@debian ~/tmp % sed 's/[^\t]*\t\([^-]*\)-[0-9][0-9]-[0-9]\([0-9]\)[^\t]*\t\([^\t]*\)/\1\t\2\t\3/' infile
    1972    1   17.0265761797993
    1972    2   17.200476457399
    1972    3   17.2926436045271
    1972    4   17.3900277599829
    1972    5   17.5987080931028
    1972    6   17.6334881486229
    1972    7   17.7030482596626
    
    • 7
  2. Best Answer
    A.B.
    2015-08-15T04:25:33+08:002015-08-15T04:25:33+08:00

    用于解析awk和date格式化日期,还有什么;)

    awk 'BEGIN {printf "%s\t%s\t%s\n","YYYY","DDD","sim"} NR != 1 {system("date -d \""$2"\" +\"%Y\t%-d\t"$3"\"")}' your_file
    

    显示一年中的第几天(使用%jinstead of%d或 better %-jinstead of %-d,-避免领先0)

    awk 'BEGIN {printf "%s\t%s\t%s\n","YYYY","DDD","sim"} NR != 1 {system("date -d \""$2"\" +\"%Y\t%-j\t"$3"\"")}' your_file
    

    例子

    输入文件

    % cat foo
    ID   date     DailyFlow
    a 1972-01-01 17.0265761797993
    b 1972-01-02 17.200476457399
    c 1972-01-03 17.2926436045271
    d 1972-01-04 17.3900277599829
    e 1972-01-05 17.5987080931028
    f 1972-01-06 17.6334881486229
    g 1972-01-07 17.7030482596626
    h 1972-02-01 17.7030482596626
    i 1972-02-02 17.7030482596626
    

    输出(带有月份的日期)

    % awk 'BEGIN {printf "%s\t%s\t%s\n","YYYY","DDD","sim"} NR != 1 {system("date -d \""$2"\" +\"%Y\t%-d\t"$3"\"")}' foo
    YYYY    DDD sim
    1972    1   17.0265761797993
    1972    2   17.200476457399
    1972    3   17.2926436045271
    1972    4   17.3900277599829
    1972    5   17.5987080931028
    1972    6   17.6334881486229
    1972    7   17.7030482596626
    1972    1   17.7030482596626
    1972    2   17.7030482596626
    

    输出(一年中的第几天)

    % awk 'BEGIN {printf "%s\t%s\t%s\n","YYYY","DDD","sim"} NR != 1 {system("date -d \""$2"\" +\"%Y\t%-j\t"$3"\"")}' foo
    YYYY    DDD sim
    1972    1   17.0265761797993
    1972    2   17.200476457399
    1972    3   17.2926436045271
    1972    4   17.3900277599829
    1972    5   17.5987080931028
    1972    6   17.6334881486229
    1972    7   17.7030482596626
    1972    32  17.7030482596626
    1972    33  17.7030482596626
    
    • 2
  3. chaos
    2015-08-15T03:30:22+08:002015-08-15T03:30:22+08:00

    使用awk:

    awk 'BEGIN{print "YYYY\tDDD\tsim"} NR!=1{printf "%s\t%s\t%s\n",substr($2,0,5),$1,$3}' file
    

    解释

    1. 该BEGIN{}部分格式化标题行。
    2. NR!=1省略文件的标题行
    3. printf()格式化输出
    4. substr($2,0,5)从日期中删除日和月

    输出看起来:

    YYYY    DDD     sim
    1972    1       17.0265761797993
    1972    2       17.200476457399
    1972    3       17.2926436045271
    1972    4       17.3900277599829
    1972    5       17.5987080931028
    1972    6       17.6334881486229
    1972    7       17.7030482596626
    
    • 1
  4. heemayl
    2015-08-15T12:38:15+08:002015-08-15T12:38:15+08:00

    仅使用bash:

    #!/bin/bash
    shopt -s extglob
    printf "YYYY\tDDD\tsim\n"
    while IFS=$'\t' read -r first second third; do
        day="$(date --date="$second" '+%j')"
        printf "%s\t%s\t%s\n" "${second%%-*}" "${day##*(0)}" "${third}"
    done < <(tail -n +2 foo.txt)
    
    • 我们从第二行开始读取输入文件的每一行,并将制表符分隔的部分作为变量first,second然后third依次

    • 然后我们使用bash参数扩展来获得我们想要的输出模式。从GNU 文档中阅读参数扩展。

    • extglob用于从天数中删除填充的零。

    例子 :

    输入 :

    ID  date        DailyFlow
    a   1972-01-01  17.0265761797993
    b   1972-01-02  17.200476457399
    c   1972-01-03  17.2926436045271
    d   1972-01-04  17.3900277599829
    e   1972-01-05  17.5987080931028
    f   1972-01-06  17.6334881486229
    g   1972-01-07  17.7030482596626
    h   1972-02-01  17.7030482596626
    i   1972-02-02  17.7030482596626
    

    输出 :

    YYYY    DDD   sim
    1972    1     17.0265761797993
    1972    2     17.200476457399
    1972    3     17.2926436045271
    1972    4     17.3900277599829
    1972    5     17.5987080931028
    1972    6     17.6334881486229
    1972    7     17.7030482596626
    1972    32    17.7030482596626
    1972    33    17.7030482596626
    
    • 1

相关问题

  • 同时复制到两个位置

  • 如何在 shell 脚本中创建选择菜单?

  • 从 bash 迁移到 zsh [关闭]

  • bashrc 还是 bash_profile?

  • 备份 bash 脚本未压缩其 tarball

Sidebar

Stats

  • 问题 205573
  • 回答 270741
  • 最佳答案 135370
  • 用户 68524
  • 热门
  • 回答
  • Marko Smith

    如何运行 .sh 脚本?

    • 16 个回答
  • Marko Smith

    如何安装 .tar.gz(或 .tar.bz2)文件?

    • 14 个回答
  • Marko Smith

    如何列出所有已安装的软件包

    • 24 个回答
  • Marko Smith

    无法锁定管理目录 (/var/lib/dpkg/) 是另一个进程在使用它吗?

    • 25 个回答
  • Martin Hope
    Flimm 如何在没有 sudo 的情况下使用 docker? 2014-06-07 00:17:43 +0800 CST
  • Martin Hope
    Ivan 如何列出所有已安装的软件包 2010-12-17 18:08:49 +0800 CST
  • Martin Hope
    La Ode Adam Saputra 无法锁定管理目录 (/var/lib/dpkg/) 是另一个进程在使用它吗? 2010-11-30 18:12:48 +0800 CST
  • Martin Hope
    David Barry 如何从命令行确定目录(文件夹)的总大小? 2010-08-06 10:20:23 +0800 CST
  • Martin Hope
    jfoucher “以下软件包已被保留:”为什么以及如何解决? 2010-08-01 13:59:22 +0800 CST
  • Martin Hope
    David Ashford 如何删除 PPA? 2010-07-30 01:09:42 +0800 CST

热门标签

10.10 10.04 gnome networking server command-line package-management software-recommendation sound xorg

Explore

  • 主页
  • 问题
    • 最新
    • 热门
  • 标签
  • 帮助

Footer

AskOverflow.Dev

关于我们

  • 关于我们
  • 联系我们

Legal Stuff

  • Privacy Policy

Language

  • Pt
  • Server
  • Unix

© 2023 AskOverflow.DEV All Rights Reserve