2017-01-27 33 views
5

我正在尝试使用awk类似于使用Rebol 3通过bash管道和工具处理更大文本文件的工具。在Rebol 3中,我在逐行读取STDIN时遇到问题?Rebol 3:有效地逐行读取STDIN(使awk像工具一样)

例如这个外壳命令产生3行:

$ (echo "first line" ; echo "second line" ; echo "third line") 
first line 
second line 
third line 

但雷博尔的输入字读取同时所有3条线。我期望它停在换行符,因为它会停止,如果你使用交互输入。

r3 --do 'while [ x: input ] [ if empty? x [ break ] print x print "***" ]' 
abcdef 
abcdef 
*** 
blabla 
blabla 
*** 

但是当我运行它一起这一次读取整个输入。我可以一次读完所有内容并分成几行,但我希望它能够以“流式”方式工作,因为我通常在许多1000-s行中使用cat

$ (echo "first line" ; echo "second line" ; echo "third line") \ 
    | r3 --do 'while [ x: input ] [ if empty? x [ break ] print x print "***" ]' 
first linesecond linethird line 
*** 

我也看了输入的来源做出了类似的功能。我可以在的每个字符中读取字符,而循环并检查换行符,但这看起来效率不高。

回答

4

我想通了,即使在10000行的大文件上,它也能很好地工作。它可以写得更优雅,但是可以改进。

功能r3awk需要STDIN,并且它每行执行,线变量绑定到它的代码块:

r3awk: func [ code /local a lines line partial ] [ 
    partial: copy "" 
    lines: read/lines/string system/ports/input 
    while [ not empty? lines ] [ 
     lines/1: rejoin [ partial lines/1 ] 
     partial: pull lines 
     foreach line lines [ 
      do bind code 'line 
     ] 
     if error? try [ lines: read/lines/string system/ports/input ] [ lines: copy [] ] 
    ] 
    line: partial 
    do bind code 'line 
]  

它的工作原理是这样的。 read /行从流中读取多个字符并返回一行代码块。每次它被调用时,它会读取下一批像这样的字符,所以它都被封装在一个while循环中。代码处理(做代码块)为while循环(不在最后)。

这批字符并不以换行符结束,所以最后一行是部分每次。下一批的第一行也是如此,因此它们将它们结合在一起。最后它必须处理最后一个(这次是非部分)线。 尝试是否有因为某些行导致utf编码错误。

它可以像这样使用命令行:

(echo "first line" ; echo "second line" ; echo "third line") | \ 
r3 --import utils.r --do 'r3awk [ parse line [ copy x to space (print x) ] ]' 
first 
second 
third 

事情,以改善:使功能一般较好,重复数据删除部分代码。如果读取/行确实在换行符上结束,请检查会发生什么情况。

+0

约好找'读取标准输入/ lines'缓冲。但是它在MacOS(OSX)上对我没有任何作用::(而不是'block!'它返回一个34815字节的“二进制!”(直到STDIN耗尽)。NB。实际上'/ lines'和'/ string')在MacOS上不做任何事情:( – draegtun

3

几年前我遇到了与input相同的问题。我不认为这是一个计划中的改变,而是一个不完整的实施(碰木头!)。

这是我当时写的解决方法函数(这对我在MacOS & Linux中工作正常)。

input-line: function [ 
    {Return next line (string!) from STDIN. Returns NONE when nothing left} 
    /part size [integer!] "Internal read/part (buffer) size" 
    ][ 
    buffer: {} ;; static 
    if none? part [size: 1024] 

    forever [ 
     if f: find buffer newline [ 
      remove f ;; chomp newline (NB. doesn't cover Windows CRLF?) 
      break 
     ] 

     if empty? data: read/part system/ports/input size [ 
      f: length? buffer 
      break 
     ] 

     append buffer to-string data 
    ] 

    unless all [empty? data empty? buffer] [take/part buffer f] 
] 

用例:

while [not none? line: input-line] [ 
    ;; do something with LINE of data from STDIN 
]