繁体   English   中英

需要在 awk 脚本中保留列间距

[英]need to retain column spacing in awk script

看到了大量的例子,但我似乎无法从https://stackoverflow.com/a/72720612这个网站上的另一个用户@Just Khaithang 在这个脚本中工作,它工作得很好,但我需要保留我的列间距为好吧,因为它很关键。 这是我在这里多次发布的 .txt 文件示例。 开头有 1 个空格,从第 1 列的开头到第 2 列的开头有 20 个空格,在 2 和 3 之间有 4 个空格。脚本见下文。 结果改变了用户输入的日期,因此使用了变量$broken_date 使用awk -v从另一个 shell 脚本调用此脚本。 工作之间的“”空格,但由于第 1 列不同,它没有保持对齐。

 146327A             0000000020220422    000002012633825-0003-1
 137149D             0000000045220419    000004512632587-0003-0
 137050C             0000000018220419    000001812632410-0003-0
 137147A             0000000045220419    000004512632487-0003-0
 137233B             0000000144220421    000014412630711-0003-1
 137599B             0000000120220419    000012012632543-0003-0
 137604D             0000000015220419    000001512632588-0003-0
 151031-001E         0000000041220517    000004112575320-0003-1
 151248-001A         0000000021220421    000002112629944-0003-1
 151249-001A         0000000005220422    000000512634524-0003-1
 151827-002B         0000000040220421    000004012629223-0003-1
 127941B             0000000045220422    000004512634676-0003-1
 137105A             0000000020220421    000002012630791-0003-1
 132136A             0000000005220419    000000512632590-0003-0
 132137A             0000000005220419    000000512632591-0003-0
 134180D             0000000052220419    000006012622399-0003-1
 134307-004K         0000000016220420    000001612635621-0003-0
 141014-001B         0000000040220419    000004012632585-0003-0

{
    c2=$2
    c3=$3
    sub("0+","",c2)
    sub("0+","",c3)
    sub("-.*","",c3)
    if (length(c2) == 8) {
        c2_value=substr(c2,1,2)
    } else if (length(c2) == 9) {
        c2_value=substr(c2,1,3)
    }

    if (length(c3) == 10) {
        c3_value=substr(c3,1,2)
    } else if (length(c3) == 11) {
        c3_value=substr(c3,1,3)
    }

    if(c2_value != c3_value) {
        sub("[1-9].*$","",$2)
        date="$broken_date"  # this value taken from user input
        print  $1"            "$2 c2_value broken_date"   "$3
    } else {
        print $0
    }
}

输出应该是

 146327A             0000000020220422    000002012633825-0003-1
 137149D             0000000045220419    000004512632587-0003-0
 137050C             0000000018220419    000001812632410-0003-0
 137147A             0000000045220419    000004512632487-0003-0
 137233B             0000000144220421    000014412630711-0003-1
 137599B             0000000120220419    000012012632543-0003-0
 137604D             0000000015220419    000001512632588-0003-0
 151031-001E         0000000041220517    000004112575320-0003-1
 151248-001A         0000000021220421    000002112629944-0003-1
 151249-001A         0000000005220422    000000512634524-0003-1
 151827-002B         0000000040220421    000004012629223-0003-1
 127941B             0000000045220422    000004512634676-0003-1
 137105A             0000000020220421    000002012630791-0003-1
 132136A             0000000005220419    000000512632590-0003-0
 132137A             0000000005220419    000000512632591-0003-0
 134180D             0000000052220909    000006012622399-0003-1
 134307-004K         0000000016220420    000001612635621-0003-0
 141014-001B         0000000040220419    000004012632585-0003-0

唯一的区别在于日期,但这就是我在输入 220909 的底部第二列的第三行需要做的事情。

我通过 MKS Toolkit 在 Korn shell 中执行此操作; awk 说文件版本为 9.2.3.2096。 这是在旧的 Windows XP 机器上。

这将与使用任何 awk 的行为相同:

$ cat tst.sh
#!/usr/bin/env bash

broken_date='220909'

awk -v broken_date="$broken_date" '
substr($2,4,7) != substr($3,1,7) {
    tail = $0
    nf = 0
    while ( tail != "" ) {
        match(tail,/^[ \t]*/)
        sep[++nf] = substr(tail,RSTART,RLENGTH)
        tail = substr(tail,RSTART+RLENGTH)
        match(tail,/^[^ \t]*/)
        fld[nf] = substr(tail,RSTART,RLENGTH)
        tail = substr(tail,RSTART+RLENGTH)
    }

    fld[2] = substr(fld[2],1,10) broken_date
    $0 = ""
    for ( i=1; i<=nf; i++ ) {
        $0 = $0 sep[i] fld[i]
    }
}
{ print }
' "${@:--}"

$ ./tst.sh file
 146327A             0000000020220422    000002012633825-0003-1
 137149D             0000000045220419    000004512632587-0003-0
 137050C             0000000018220419    000001812632410-0003-0
 137147A             0000000045220419    000004512632487-0003-0
 137233B             0000000144220421    000014412630711-0003-1
 137599B             0000000120220419    000012012632543-0003-0
 137604D             0000000015220419    000001512632588-0003-0
 151031-001E         0000000041220517    000004112575320-0003-1
 151248-001A         0000000021220421    000002112629944-0003-1
 151249-001A         0000000005220422    000000512634524-0003-1
 151827-002B         0000000040220421    000004012629223-0003-1
 127941B             0000000045220422    000004512634676-0003-1
 137105A             0000000020220421    000002012630791-0003-1
 132136A             0000000005220419    000000512632590-0003-0
 132137A             0000000005220419    000000512632591-0003-0
 134180D             0000000052220909    000006012622399-0003-1
 134307-004K         0000000016220420    000001612635621-0003-0
 141014-001B         0000000040220419    000004012632585-0003-0

它只是保留您已有的任何间距。 我使脚本比必要的更通用,因此您可以了解如何将输入记录分解为分隔符数组 ( sep[] ) 和字段 ( fld[] ),这样您以后就可以对类似问题做任何您想做的事情。

假设:

  • GNU awk/FIELDWIDTHS可供 OP 使用(在评论中 OP 提到无法让FIELDWIDTHS工作,我认为这意味着 OP 正在运行GNU awk否则我希望 OP 说明错误或FIELDWIDTHS不可用)
  • 输入字段宽度是预先知道的(例如,所有输入具有相同的间距)

修改 OP 当前代码以使用GNU awk/FIELDWIDTHS的一种想法:

broken_date='220909'

awk -v bdate="${broken_date}" '
BEGIN  { FIELDWIDTHS="21 20 100"
         fmt="%-21s%-20s%s\n"                # define our printf format to match FIELDSWIDTHS
       }
       { c2=$2; gsub(/ /,"",c2); sub("0+","",c2)
         c3=$3; gsub(/ /,"",c3); sub("0+","",c3); sub("-.*","",c3)

              if (length(c2) == 8)  { c2_value=substr(c2,1,2) }
         else if (length(c2) == 9)  { c2_value=substr(c2,1,3) }

              if (length(c3) == 10) { c3_value=substr(c3,1,2) }
         else if (length(c3) == 11) { c3_value=substr(c3,1,3) }

         if (c2_value != c3_value) { printf fmt,$1,substr($2,1,length(gensub(/ /,"","g",$2))-6) bdate,$3 }
         else                      { print $0 }
       }
' x > y

在保持FIELDWIDTHS方法的同时,重新设计 OP 逻辑(也解决length(c3) == 9问题):

broken_date='220909'

awk -v bdate="${broken_date}" '
BEGIN  { FIELDWIDTHS="21 20 100"
         fmt="%-21s%-20s%s\n"
       }
       { c2=$2;
         gsub(/^[0]+| /,"",c2 )                    # strip leading zeroes and all spaces
         c2=substr(c2,1,length(c2)-6)              # strip off last 6 characters

         pfx=$2                                    # find the prefix of $2
         gsub(/ /,"",pfx)                          # strip all spaces
         pfx=substr(pfx,1,length(pfx)-6)           # strip off last 6 characters

         split($3,a,"-")                           # split $3 on hyphens
         c3=a[1]                                   # grab 1st hyphen delimited field
         gsub(/^[0]+| /,"",c3)                     # strip leading zeroes and all spaces
         c3=substr(c3,1,length(c3)-8)              # strip off last 8 characters

         if (c2 != c3) $2=pfx bdate                # replace $2 with its prefix + bdate (aka broken_date)

         printf fmt,$1,$2,$3
       }
' x > y

这两个生成:

$ diff x y
16c16
<  134180D             0000000052220419    000006012622399-0003-1
---
>  134180D             0000000052220909    000006012622399-0003-1

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM