【问题标题】:using awk to combine multiple line elements into single line使用 awk 将多个行元素组合成单行
【发布时间】:2015-11-07 13:38:40
【问题描述】:

我需要将输入文件转换为更标准化的内容,以便 sql loader 插入 Oracle 8i 数据库(是的,我们与时俱进!)。问题是该文件被格式化为垂直列出每个行元素,所以我需要以某种方式循环它并在我创建加载所需的输出文件时建立一个有效的行。

我知道这应该是相对可以实现的,但我对所有 AWK/SED 都是全新的,虽然我通过阅读网站(例如这个)和我买的一些书取得了一些进展,时间限制意味着我需要寻求更多专家的建议来帮助我。

我相信我可以通过构建一个或多个数组然后使用 while 循环遍历其余数据来完成我需要的工作,但是虽然我可以构建数组,但我不完全确定如何链接他们在一起,或者即使我正在做的是最好的方法。

不管怎样……我已经够啰嗦了。

这是我需要处理的数据文件的一小部分。这基本上是对供应商向我们发货的书籍的确认:

UNB+UNOA:2+5060096369998:14+[BUYER GLN]:14+150310:0105+000023++DESADV'
UNH+0000001+DESADV:D:96A:UN:EAN005'
BGM+351+[INVOICE NUMBER]'
DTM+137:20150309:102'
DTM+11:20150309:102'
DTM+63:20150310:102'
NAD+BY+[BUYER GLN]::9++[BUYER NAME AND ADDRESS]'
NAD+SU+5060096369998::9++GARDNERS BOOKS LTD.+1 WHITTLE DRIVE:WILLINGDON         DROVE:EASTBOURNE+++BN23 6QH+GB'
NAD+DP+[SHIPPING GLN]::9++[SHIPPING NAME AND ADDRESS]'
CPS+1'
PAC+3++PK'
MEA+PD+AAB+KGM:11'
MEA+PD+HT+MMT:460'
MEA+PD+WD+MMT:310'
MEA+PD+LN+MMT:235'
PCI+33E'
GIN+BJ+305060096368359186'
LIN+1++9780006755227:EN'
PIA+1+0006755224:IB'
IMD+F+BST+:::DOGSBODY/JONES, DIANA WYNNE'
QTY+12:1'
RFF+ON:124705572-15-1'
LIN+2++9780007245826:EN'
PIA+1+0007245823:IB'
IMD+F+BST+:::VINTAGE AFFAIR/WOLFF, ISABEL'
QTY+12:3'
RFF+ON:124705572-62-1'
LIN+3++9780007250608:EN'
PIA+1+0007250606:IB'
IMD+F+BST+:::MYSTERY OF THE BLUE TRAIN COMIC STR'
QTY+12:1'
RFF+ON:124705572-48-1'
PAC+3++PK'
MEA+PD+AAB+KGM:11'
MEA+PD+HT+MMT:460'
MEA+PD+WD+MMT:310'
MEA+PD+LN+MMT:235'
PCI+33E'
GIN+BJ+305060096368359193'
LIN+4++9780091950309:EN'
PIA+1+0091950309:IB'IMD+F+BST+:::LOVER/JORDAN, NICOLE'
QTY+12:1'
RFF+ON:124705572-98-1'
LIN+5++9780099453956:EN'
PIA+1+0099453959:IB'IMD+F+BST+:::FLANDERS PANEL/PEREZ-REVERTE, ARTUR'
QTY+12:1'
RFF+ON:124705572-22-1'
LIN+6++9780099481379:EN'
PIA+1+0099481375:IB'
IMD+F+BST+:::MYSTERIOUS FLAME OF QUEEN LOANA/ECO'
QTY+12:2'
RFF+ON:124705572-36-1'
CNT+1:9'
CNT+2:6'
UNT+695+0000001'
UNZ+1+000023'

忽略前几行,我真正感兴趣的行是开始于 GIN(这些是单独的记录标识符)、LIN(包含书籍 ISBN)、QTY(有趣地包含数量)和 RFF(包含我们的内部参考)。

将字段分隔符设置为 [+:]+ 我需要从每个 GIN 记录开始并从该行检索 $3(这是我最初添加到我的数组中的内容)。虽然该值保持不变,但我想继续浏览文件,对于每条 LIN 记录,我想从 LIN、QTY 和 RFF 字段中获取 $3 值,并将它们打印在同一行上,包括 GIN 值。一旦 GIN 记录发生更改,我们将继续如上,但现在我们在每行的字段 1 中打印出新的 GIN 值。输出上的字段分隔符可以是空格或逗号(或其他任何东西),理想情况下,我也想去掉出现在每个值/行末尾的撇号 '。

输出最终会像下面这样(我实际上已经包含了行标识符 ($1) 以使其更容易理解,但最终打印并不真正需要它们):

GIN305060096368359186,LIN9780006755227,QTY1,RFF124705572-15-1
GIN305060096368359186,LIN9780007245826,QTY3,RFF124705572-62-1
GIN305060096368359186,LIN9780007250608,QTY1,RFF124705572-48-1
GIN305060096368359193,LIN9780091950309,QTY1,RFF124705572-98-1
GIN305060096368359193,LIN9780099453956,QTY1,RFF124705572-22-1
GIN305060096368359193,LIN9780099481379,QTY2,RFF124705572-36-1

我没有添加任何尝试,因为它们数量庞大且可能全是垃圾。完整的文件最终可能包含 30 或 40 条 GIN 记录,每个记录大约 30 条 LIN 记录。

非常感谢任何帮助。

谢谢, 菲尔

【问题讨论】:

    标签: arrays awk while-loop


    【解决方案1】:

    以下是实现此目的的方法:

    首先你需要知道它是什么类型的线:

    is_gin=`echo $i | grep "GIN+"`
    is_lin=`echo $i | grep "LIN+"`
    is_qty=`echo $i | grep "QTY+"`
    is_rff=`echo $i | grep "RFF+"`
    

    那么您需要对这些中的每一个进行特定处理:

    只取这个数字

    gin=`echo $i | grep -o '[0-9]*'`
    

    删除 ++ 之前的所有内容,之后只取数字

    linreq=`echo $i | sed 's/.*++//g' | grep -o '[0-9]*'`
    

    取 : 之后的所有数字并删除 : 之后

    qty=`echo $i | grep -o ':[0-9]*' | sed -e 's/://g'`
    

    只取 XXXXX-XXXX-XXXX 模式(与 X 一样多)

    rff=`echo $i  | grep -o '[0-9]*-[0-9]*-[0-9]*'`
    

    那么这只是几个处理循环并检查新行。这是你的脚本:processing.sh input_file output_file

    #!/bin/bash
    
    IFS=$'\n' #line delimiter
    
    #empty your output file
    cp /dev/null "$2"
    
    for i in $(cat "$1"); do
        
        is_gin=`echo $i | grep "GIN+"`
        is_lin=`echo $i | grep "LIN+"`
        is_qty=`echo $i | grep "QTY+"`
        is_rff=`echo $i | grep "RFF+"`
    
        if [ ! -z "$is_gin" ]; then
            #gin=`echo $i | grep -o '[0-9]*'`
            gin=`echo $i | awk 'match($0,/[0-9]{1,}/) {print substr($0,RSTART,RLENGTH)}'`
            newline=0
            linecontent="GIN${gin},"
        elif [ ! -z "$is_lin" ]; then
            #linreq=`echo $i | sed 's/.*++//g' | grep -o '[0-9]*'`
            linreq=`echo $i | sed 's/.*++//g' | awk 'match($0,/[0-9]{1,}/) {print substr($0,RSTART,RLENGTH)}'`
            if [ -z "$linecontent" ]; then
                linecontent="GIN${gin},LIN${linreq},"
            else
                linecontent="${linecontent}LIN${linreq},"
            fi
        elif [ ! -z "$is_qty" ]; then
            #qty=`echo $i | grep -o ':[0-9]*' | sed -e 's/://g'`
            qty=`echo $i | awk 'match($0,/:[0-9]{1,}/) {print substr($0,RSTART,RLENGTH)}' | sed -e 's/://g'`
            linecontent="${linecontent}QTY${qty},"
        elif [ ! -z "$is_rff" ]; then
            #rff=`echo $i  | grep -o '[0-9]*-[0-9]*-[0-9]*'`
            rff=`echo $i  | awk 'match($0,/[0-9]{1,}-[0-9]{1,}-[0-9]{1,}/) {print substr($0,RSTART,RLENGTH)}'`
            linecontent="${linecontent}RFF${rff}"
            echo $linecontent >> "$2"
            linecontent=""
        fi
    
    done
    
    cat $2
    

    输出:

    GIN305060096368359186,LIN9780006755227,QTY1,RFF124705572-15-1
    GIN305060096368359186,LIN9780007245826,QTY3,RFF124705572-62-1
    GIN305060096368359186,LIN9780007250608,QTY1,RFF124705572-48-1
    GIN305060096368359193,LIN9780091950309,QTY1,RFF124705572-98-1
    GIN305060096368359193,LIN9780099453956,QTY1,RFF124705572-22-1
    GIN305060096368359193,LIN9780099481379,QTY2,RFF124705572-36-1
    

    我添加了 awk 符号,它也可以满足您的需要

    要点:https://gist.github.com/bertrandmartel/771b2371c0050b658fcd

    【讨论】:

    • 嗨 Bertrand - 感谢您的快速回复。从来没有想过只使用 grep 和 sed,非常感谢 - 我现在遇到了一个错误,虽然说 grep -o 不是一个有效的选项。可能我们使用的是旧版本,所以我可以期待更新。
    • 哦,也许你不在 Unix 机器上。但是不用担心,如果您有权访问 awk,则可以将所有 grep -o 'regex' 替换为 awk 'match($0,/regex/) {print substr($0,RSTART,RLENGTH)}'
    • 我更新了我的答案,只使用 awk 而没有 grep。我希望它对你有用
    • 不幸的是,我们使用的是相当老的 AIX,但我确实可以访问 awk,所以我已经按照您的建议进行了调整,然后宾果游戏!完美,正是我想要的。非常感谢您的 Bertrand,我无法告诉您我对您的时间和帮助的感激之情。
    • 不客气,很高兴你成功了。如果您的问题得到解决,您可以点击接受此答案
    猜你喜欢
    • 2020-01-07
    • 2017-03-23
    • 2017-02-05
    • 1970-01-01
    • 2023-03-12
    • 1970-01-01
    • 2021-09-02
    • 2018-02-17
    • 1970-01-01
    相关资源
    最近更新 更多