【问题标题】:Format and then convert txt to csv using shell script and awk使用 shell 脚本和 awk 格式化然后将 txt 转换为 csv
【发布时间】:2018-09-25 16:35:56
【问题描述】:

我有一个文本文件:

ifile.txt
x       y       z       t              value
1       1       5       01hr01Jan2018   3
1       1       5       02hr01Jan2018   3.1
1       1       5       03hr01Jan2018   3.2
1       3.4     3       01hr01Jan2018   4.1
1       3.4     3       02hr01Jan2018   6.1
1       3.4     3       03hr01Jan2018   1.1
1       4.2     6       01hr01Jan2018   6.33
1       4.2     6       02hr01Jan2018   8.33
1       4.2     6       03hr01Jan2018   5.33
3.4     1       2       01hr01Jan2018   3.5
3.4     1       2       02hr01Jan2018   5.65
3.4     1       2       03hr01Jan2018   3.66
3.4     3.4     4       01hr01Jan2018   6.32
3.4     3.4     4       02hr01Jan2018   9.32
3.4     3.4     4       03hr01Jan2018   12.32
3.4     4.2     8.1     01hr01Jan2018   7.43
3.4     4.2     8.1     02hr01Jan2018   7.93
3.4     4.2     8.1     03hr01Jan2018   5.43
4.2     1       3.4     01hr01Jan2018   6.12
4.2     1       3.4     02hr01Jan2018   7.15
4.2     1       3.4     03hr01Jan2018   9.12
4.2     3.4     5.5     01hr01Jan2018   2.2
4.2     3.4     5.5     02hr01Jan2018   3.42
4.2     3.4     5.5     03hr01Jan2018   3.21
4.2     4.2     6.2     01hr01Jan2018   1.3
4.2     4.2     6.2     02hr01Jan2018   3.4
4.2     4.2     6.2     03hr01Jan2018   1

说明:每个坐标 (x,y) 都有一个 z 值和三个时间值。空格不是制表符。它们是空格序列。

我想将 t 列格式化为行,然后转换为 csv 文件。我的预期输出为:

ofile.txt
x,y,z,01hr01Jan2018,02hr01Jan2018,03hr01Jan2018
1,1,5,3,3.1,3.2
1,3.4,3,4.1,6.1,1.1
1,4.2,6,6.33,8.33,5.33
3.4,1,2,3.5,5.65,3.66
3.4,3.4,4,6.32,9.32,12.32
3.4,4.2,8.1,7.43,7.93,5.43
4.2,1,3.4,6.12,7.15,9.12
4.2,3.4,5.5,2.2,3.42,3.21
4.2,4.2,6.2,1.3,3.4,1

我正在尝试以下方式,但仍然没有得到期望的输出。我的脚本在末尾打印了一些额外的逗号 (,)。

我的算法和脚本是:

    #Step1:- Split into two files: one with x,y,z (0001.txt) and
    #        another with t,value (0002.txt).

    awk '{n=3; for (i=1;i<=n;i++) printf "%s ", $i; print "";}' ifile.txt > 0001.txt
    awk '{n=5; for (i=4;i<=n;i++) printf "%s ", $i; print "";}' ifile.txt > 0002.txt

    #Setp2:- In 0001.txt: Delete the repetition rows. 

    awk '!seen[$1,$2,$3]++' 0001.txt > 00011.txt

    #Step3:- In 0002.txt: Delete the first row. For each 3 rows in t-column,
    #        write the value-column as rows. Add the t-row at top
    #        this is very manual. I am wondering for some command

    grep -E "^[0-9].*" 0002.txt > 0003.txt
   awk -v n=3 '{ row = row $2 " "; if (NR % n == 0) { print row; row = "" } }' 0003.txt > 0004.txt
    (echo "01hr01Jan2018,02hr01Jan2018,03hr01Jan2018";cat 0004.txt) > 00022.txt  

    #Step4:- Paste output of two and convert to csv.
    paste 00011.txt 00022.txt > 0005.txt
    cat 0005.txt | tr -s '[:blank:]' ',' > ofile.txt

【问题讨论】:

    标签: linux shell awk


    【解决方案1】:

    你可以使用这个awk:

    awk -v OFS=, '{k=$1 OFS $2 OFS $3}
    !($4 in hdr){hn[++h]=$4; hdr[$4]}
    k in row{row[k]=row[k] OFS $5; next}
    {rn[++n]=k; row[k]=$5}
    END {
       printf "%s", rn[1]
       for(i=1; i<=h; i++)
          printf "%s", OFS hn[i]
       print ""
       for (i=2; i<=n; i++)
          print rn[i], row[rn[i]]
    }' file
    

    x,y,z,t,01hr01Jan2018,02hr01Jan2018,03hr01Jan2018
    1,1,5,3,3.1,3.2
    1,3.4,3,4.1,6.1,1.1
    1,4.2,6,6.33,8.33,5.33
    3.4,1,2,3.5,5.65,3.66
    3.4,3.4,4,6.32,9.32,12.32
    3.4,4.2,8.1,7.43,7.93,5.43
    4.2,1,3.4,6.12,7.15,9.12
    4.2,3.4,5.5,2.2,3.42,3.21
    4.2,4.2,6.2,1.3,3.4,1
    

    【讨论】:

    • 谢谢。我想更改 t 的格式。仅从字母数字到数字。所需格式为 YYYYMMDDHHMin。即01hr01Jan2018,02hr01Jan2018,03hr01Jan2018201801010100,201801010200,201801010300。可以请教一下怎么做吗?
    • 更改日期格式不会很直接,因为01hr01Jan2018 不是标准格式。如果你不能保持目前的格式,那么请告诉我,我将不得不再写几行代码来转换。
    • 非常感谢。本质上,我需要它。我在stackoverflow.com/questions/52504138/… 的另一个问题中问过它
    【解决方案2】:

    单个 awk 程序可以生成您想要的输出:使用 GNU awk

    gawk '
        BEGIN {SUBSEP = OFS = ","}
        NR==1 {next}
        { groups[$4]; value[$1,$2,$3][$4] = $5 }
        END {
            PROCINFO["sorted_in"] = "@ind_str_asc"
            printf "x,y,z"
            for (g in groups) printf ",%s", g
            printf "\n"
            for (a in value) {
                printf "%s", a
                for (g in groups) printf "%s%s", OFS, 0+value[a][g]
                printf "\n"
            }
        }
    ' ifile.txt
    

    【讨论】:

      【解决方案3】:

      另一个类似的awk,没有正确的标题

      $ awk -v OFS=, '{k=$1 OFS $2 OFS $3} 
                 p!=k {if(p) print line; p=k; line=k} 
                      {line=line OFS $NF} 
                 END  {print line}' file 
      
      x,y,z,value
      1,1,5,3,3.1,3.2
      1,3.4,3,4.1,6.1,1.1
      1,4.2,6,6.33,8.33,5.33
      3.4,1,2,3.5,5.65,3.66
      3.4,3.4,4,6.32,9.32,12.32
      3.4,4.2,8.1,7.43,7.93,5.43
      4.2,1,3.4,6.12,7.15,9.12
      4.2,3.4,5.5,2.2,3.42,3.21
      4.2,4.2,6.2,1.3,3.4,1
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2017-01-31
        • 2019-08-05
        • 1970-01-01
        • 2016-09-21
        • 2018-06-23
        • 2017-05-10
        • 1970-01-01
        相关资源
        最近更新 更多