使用shell脚本和awk将txt格式化,然后转换为csv格式

1 人关注

我有一个文本文件。

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
Kay
Kay
发布于 2018-09-26
3 个回答
anubhava
anubhava
发布于 2018-09-26
已采纳
0 人赞同

你可以使用这个 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
4.2,4.2,6.2,1.3,3.4,1
    
Kay
谢谢你。我想改变T的格式,从字母数字改为数字。希望的格式是YYYMMDDHHMin。也就是 01hr01Jan2018,02hr01Jan2018,03hr01Jan2018 201801010100,201801010200,201801010300 。能否请您建议如何做?
改变日期格式并不容易,因为 01hr01Jan2018 并不是一个标准格式。如果你不能保持目前的格式,请告诉我,我将不得不多写几行代码来转换。
Kay
非常感谢你。基本上,我需要它。我已经在这里提出了一个单独的问题 stackoverflow.com/questions/52504138/...
glenn jackman
glenn jackman
发布于 2018-09-26
0 人赞同

一个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
    
karakfa
karakfa
发布于 2018-09-26
0 人赞同

另一个类似的 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