2017-01-27 76 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 
]