awk:来自管道的进程输入,在输出文件中的pattern之前插入结果

时间:2014-08-07 02:50:17

标签: regex awk scripting

我正在尝试通过简单的awk函数处理输入流,并将结果插入现有文件中的锚点模式之前。我的功能很好,但是我不能说服awk把结果写在我想要的地方和方式上。输入被作为XML从hunspell传送到我的脚本,该脚本接受输出文件作为参数。

hunspell -L -H ./text.xml | ./parse.awk ./output.xml

#!/usr/bin/awk -f
#

function buildObjs()
{
    a["x"]=$4*mils; a["y"]=-$5*mils; a["w"]=$6*mils; a["h"]=$7*mils
    print "## element" NR+1 " [x]="a["x"]" [y]="a["y"]" [width]="a["w"]" [height]="a["h"]
    print "set fsize("NR+1") {FALSE}"
    print "set fmargin("NR+1") {FALSE}"
    print "set fmaster("NR+1") {TRUE}"
    print "set ftype("NR+1") {box}"
    print "set fname("NR+1") {"a["w"],a["h"]"}"
    print "set fatt("NR+1") {1}"
    print "set dplObjectSetup("NR+1",TRA) {"a["x"],a["y"]"}"
    print "set fnum("NR+1") {}"
    return 0
}

BEGIN {
    FS = "[\" ]+"
    mils = "0.3527"
    for (i = 0; i < ARGC; i++) {
        # Use this block to identify the output file we need to write to.
        if (ARGV[i] ~ /output.+/) {
            outFile=ARGV[i]
            delete ARGV[i]
        }
    }
    while ((getline line < outFile) > 0) {
        if (line ~ !/set lineno \{.+\}/) {
            print line
        }
    }
    close(outFile)
}

{
    buildObjs()
}

END {
    print "set lineno {"NR+2"}"
    while ((getline line < outFile) > 0) {
        if (line ~ /set mode \{.+\}/) {
            print line
        } else
            print line
    }
    close(outFile)
}

我在outFile中寻找的锚模式是&#34;设置lineno {3}&#34;。在来自text.xml的流中,有20行,并且buildObjs函数在每行输入上循环,这意味着我在输出文件中定义了20个对象,在我去的时候用NR + 1迭代对象计数。要处理的行数因作业而异。作为奖励问题,需要更新锚模式,以便设置lineno {3}&#34;成为&#34;设置lineno {NR + 2}&#34;无论NR + 2如何解决这项工作。大概我会在END块中执行此操作,但是现在我只需要将新对象放入输出文件中。

总而言之,将输入流输入到我的awk脚本中,使用我的函数处理它,将结果插入现有文件中的模式之前,更新锚模式并关闭修改后的文件。这是我在bash脚本中嵌入的单行之外的第一次大量使用awk。非常感谢任何帮助。

编辑:我已更新代码以反映Jonathan的评论。

EDIT2:更新了END块。这段代码现在做了我想要的。

EDIT3:以下是我的脚本中输入的几行:

<w box="45.2044 92.54 61.5253 9.503" xoffset="6.27627 12.6244 19.4125 25.5994 32.2113 38.159 48.5253">Technews</w>

<w box="407.31 91.6 107.774 10.443" xoffset="1.8024 6.7944 12.1711 18.8203 29.2284 36.5576 43.2034 50.0661 56.641 61.0251 68.0434 74.6553 85.0634 92.0651 97.1957 100.274">Issue256:June27th</w>

<w box="67.923 132.463 32.747 7.337" xoffset="6.259 14.168 19.129 21.747">DALIM</w>

outFile的摘录:

#    file.encoding: UTF-8
# sun.jnu.encoding: UTF-8

set toolVersion {1.20}
set ftype(0) {pgs}
set fsize(0) {FALSE}
set fmargin(0) {FALSE}
set fsize(1) {TRUE}
set fmargin(1) {TRUE}
set fmaster(1) {FALSE}
set ftype(1) {pgs}
set fname(1) {}
set fatt(1) {0}
set dplObjectSetup(1,TRA) {}
set fnum(1) {}
>> New data inserted here.
set lineno {2} << This number updated to reflect the total number of objects.
set mode {1}
set preservePDF {1}
set preservePDFAction {Continue}

所以,正如我希望这澄清一样,在处理管道输入后,我要插入以&#34开头的附加块;设置fsize()&#34;以&#34;结束fnum()&#34;结束,按照我的方式递增,并总结&#34; set lineno {}&#34;中的块总数。最后在&#34;设置lineno {}&#34;。

之后追加尾随行

2 个答案:

答案 0 :(得分:0)

主要操作{ buildObjs(); PROFIT??; }(对于PROFIT??意味着什么)对每一行都起作用,因为它之前没有模式。您应该添加一个模式以识别您想要添加输出的位置:

/set lineno \{3\}/ { buildObjs() }
                   { print }

第一个识别模式({awk正则表达式元字符,因此必须对其进行转义),第二个确保在buildObjs()的输出之后打印该行。如果你想让set lineno {3}先到,那就颠倒一行。

答案 1 :(得分:0)

这是您的可执行awk脚本的修改版本,可生成您想要的顺序:

#!/usr/bin/awk -f

BEGIN { FS="[{}]"; mils="0.3527"; built=1 }

FNR==NR {
    if( $1 !~ /set lineno/ ) {
        if( lineno != "" ) { footer[++cnt]=$0; if(cnt==3) { FS = "[\" ]+" } }
        else print
    }
    else { lineno=$2 }
    next
}

FNR!=NR && NF > 0 { built += buildObjs( built+1 ) }

END {
    print "set lineno {" built "}"
    for(i=1;i<=cnt;i++ ) {
        print footer[i]
    }
}

function buildObjs( n )
{
    x=$4*mils; y=-$5*mils; w=$6*mils; h=$7*mils
    print "## element" n " [x]=" x " [y]=" y " [width]=" w " [height]=" h
    print "set fsize(" n ") {FALSE}"
    print "set fmargin(" n ") {FALSE}"
    print "set fmaster(" n ") {TRUE}"
    print "set ftype(" n ") {box}"
    print "set fname(" n ") {" w " " h "}"
    print "set fatt(" n ") {1}"
    print "set dplObjectSetup(" n ",TRA) {" x " " y "}"
    print "set fnum(" n ") {}"
    return 1
}

当放入名为awko的文件时,它将像:

一样运行
hunspell -L -H ./text.xml | ./awko ./output.xml -

我没有安装hunspell,所以我通过cat运行文件的Edit3管道输出来测试它:

cat ./pipeddata | ./awko ./output.xml -

注意输出文件后面的-告诉awkstdin读取awk脚本的第二个输入,这让我可以使用标准的FNR==NR { do stuff; next }逻辑来处理第一个文件。

以下是细分:

  • 对于个人偏好,我将buildObjs()功能移到了脚本的末尾。注意我添加了一个n参数 - NR不会在输出中使用。我删除了a数组,因为它似乎没有必要,并且已将其更改为从0返回1
  • BEGIN块中,设置output.xml文件解析和mils
  • 每当FILENAME更改为-时,请更改FS以解析该输入。可以在输出文件和FS之间的命令行上设置管道数据-
  • FNR==NR处理第一个文件时
  • 基本上,打印&#34;标题&#34;当你的主页没有被阅读时的信息
  • 阅读锚点后,将其存储在lineno
  • 读取锚点后,将output文件的最后一个文件按footer顺序存储到cnt数组中。知道最后只有3行,我被欺骗了#34;在从FS读取第一条记录之前调整STDIN
  • FNR!=NR且该行不空白(NF>0)时,处理管道输入,递增built并将其传递为1的偏移量buildObjs()的arg(因为built的值为0)。
  • END中,使用set linenolineno的总和重建/打印built行。
  • 然后根据cnt变量
  • 按顺序打印第一个文件中的页脚

使用cat表单,我得到以下信息:

#    file.encoding: UTF-8
# sun.jnu.encoding: UTF-8

set toolVersion {1.20}
set ftype(0) {pgs}
set fsize(0) {FALSE}
set fmargin(0) {FALSE}
set fsize(1) {TRUE}
set fmargin(1) {TRUE}
set fmaster(1) {FALSE}
set ftype(1) {pgs}
set fname(1) {}
set fatt(1) {0}
set dplObjectSetup(1,TRA) {}
set fnum(1) {}
## element2 [x]=32.6389 [y]=-21.7 [width]=3.35171 [height]=0
set fsize(2) {FALSE}
set fmargin(2) {FALSE}
set fmaster(2) {TRUE}
set ftype(2) {box}
set fname(2) {3.35171 0}
set fatt(2) {1}
set dplObjectSetup(2,TRA) {32.6389 -21.7}
set fnum(2) {}
## element3 [x]=32.3073 [y]=-38.0119 [width]=3.68325 [height]=0
set fsize(3) {FALSE}
set fmargin(3) {FALSE}
set fmaster(3) {TRUE}
set ftype(3) {box}
set fname(3) {3.68325 0}
set fatt(3) {1}
set dplObjectSetup(3,TRA) {32.3073 -38.0119}
set fnum(3) {}
## element4 [x]=46.7197 [y]=-11.5499 [width]=2.58776 [height]=0
set fsize(4) {FALSE}
set fmargin(4) {FALSE}
set fmaster(4) {TRUE}
set ftype(4) {box}
set fname(4) {2.58776 0}
set fatt(4) {1}
set dplObjectSetup(4,TRA) {46.7197 -11.5499}
set fnum(4) {}
set lineno {4}
set mode {1}
set preservePDF {1}
set preservePDFAction {Continue}

似乎你的buildObj()函数逻辑需要注意以你想要的方式得到东西(我怀疑你选择的索引需要转移)。