Düğümde stdin satır satır okuma


177

Bir komut satırı çağrısı kullanarak düğümü olan bir metin dosyasını işlemek için arıyorum:

node app.js < input.txt

Dosyanın her satırının ayrı ayrı işlenmesi gerekir, ancak işlendikten sonra giriş satırı unutulabilir.

Stdin'in veri dinleyicisini kullanarak, giriş buharını bir bayt boyutuyla parçalandırıyorum, bu yüzden bunu ayarladım.

process.stdin.resume();
process.stdin.setEncoding('utf8');

var lingeringLine = "";

process.stdin.on('data', function(chunk) {
    lines = chunk.split("\n");

    lines[0] = lingeringLine + lines[0];
    lingeringLine = lines.pop();

    lines.forEach(processLine);
});

process.stdin.on('end', function() {
    processLine(lingeringLine);
});

Ama bu çok özensiz görünüyor. Hatları dizinin ilk ve son öğeleri etrafında masaj olması. Bunu yapmanın daha zarif bir yolu yok mu?

Yanıtlar:


207

Stdin'den satır satır okumak için readline modülünü kullanabilirsiniz :

var readline = require('readline');
var rl = readline.createInterface({
  input: process.stdin,
  output: process.stdout,
  terminal: false
});

rl.on('line', function(line){
    console.log(line);
})

3
Bu, konsolda elle giriş girmek için iyi çalışıyor gibi görünüyor, ancak, bir dosyayı komutun içine ilettiğimde dosya stdout'a gönderiliyor. Bir böcek? readline bu noktada kararsız kabul edilir.
Matt R. Wilson

1
Sanırım sadece process.stdoutfarklı bir yazılabilir akışa geçebilirsiniz - bu kadar basit olabiliroutput: new require('stream').Writable()
Jeff Sisson 20:13

3
Ne yazık ki, stdout'a ihtiyacım var. Sorumdan ayrıldım, ancak uygulamayı kullanılabilir olarak kullanmaya çalışıyorum node app.js < input.txt > output.txt.
Matt R. Wilson

Görünüşe göre bu 'tasarımla' github.com/joyent/node/issues/4243#issuecomment-10133900 . Dediğim gibi yaptım ve çıktı seçeneğine kukla yazılabilir bir akış sağladım, sonra doğrudan stdout akışına yazdım. Sevmiyorum, ama işe yarıyor.
Matt R. Wilson

13
terminal: falseCreateInterface için bağımsız değişkeni iletirseniz, bu sorunu giderir.
jasoncrawford

61
// Work on POSIX and Windows
var fs = require("fs");
var stdinBuffer = fs.readFileSync(0); // STDIN_FILENO = 0
console.log(stdinBuffer.toString());

3
Bazı ayrıntılar ekleyebilir misiniz? Zaten yüksek derecede kabul edilmiş bir cevap var
jhhoff02

2
Bu benim için işe yaramıyor (düğüm v9.2.0, Windows). Error: EISDIR: illegal operation on a directory, fstat at tryStatSync (fs.js: 534: 13) `
AlexChaffee

2
OSX v6.11.2 düğümünde benim için çalıştı.
şifon

3
@AlexChaffee: Stdin girişi yoksa veya stdin kapalıysa Windows'ta bir hata var (v9.10.1'den itibaren hala mevcut) - bu GitHub sorununa bakın . Bunun dışında, ancak, çözüm yapar Windows üzerinde çalışmalarını.
mklement0

3
çok iyi çalışıyor ve bugüne kadar en kısa, yaparak daha kısa yapabilirfs.readFileSync(0).toString()
localhostdotdev

56

readlineözellikle terminal ile çalışacak şekilde tasarlanmıştır (yani process.stdin.isTTY === true). Gibi jenerik akışları için bölünmüş işlevsellik sağlamak modüllerin bir yeri vardır bölünmüş . İşleri süper kolaylaştırır:

process.stdin.pipe(require('split')()).on('data', processLine)

function processLine (line) {
  console.log(line + '!')
}

6
hayır değil. Satır satır okumak istemiyorsanız buna hiç ihtiyacınız yoktur
vkurchatkin

6
İpucu: Tüm satırları işledikten sonra bir kod çalıştırmak istiyorsanız .on('end', doMoreStuff), ilk satırdan sonra ekleyin .on(). Kodu, ifadeden sonra normal şekilde yazarsanız, .on()herhangi bir giriş okunmadan önce bu kodun çalışacağını unutmayın, çünkü JavaScript senkronize değildir.
Rory O'Kane

14
#!/usr/bin/env node

const EventEmitter = require('events');

function stdinLineByLine() {
  const stdin = new EventEmitter();
  let buff = "";

  process.stdin
    .on('data', data => {
      buff += data;
      lines = buff.split(/[\r\n|\n]/);
      buff = lines.pop();
      lines.forEach(line => stdin.emit('line', line));
    })
    .on('end', () => {
      if (buff.length > 0) stdin.emit('line', buff);
    });

  return stdin;
}

const stdin = stdinLineByLine();
stdin.on('line', console.log);

0

diğerleri için paylaşım:

akışı satır satır okumak, benim sürüm: stdin içine borulu büyük dosyalar için iyi olmalıdır:

var n=0;
function on_line(line,cb)
{
    ////one each line
    console.log(n++,"line ",line);
    return cb();
    ////end of one each line
}

var fs = require('fs');
var readStream = fs.createReadStream('all_titles.txt');
//var readStream = process.stdin;
readStream.pause();
readStream.setEncoding('utf8');

var buffer=[];
readStream.on('data', (chunk) => {
    const newlines=/[\r\n]+/;
    var lines=chunk.split(newlines)
    if(lines.length==1)
    {
        buffer.push(lines[0]);
        return;
    }   

    buffer.push(lines[0]);
    var str=buffer.join('');
    buffer.length=0;
    readStream.pause();

    on_line(str,()=>{
        var i=1,l=lines.length-1;
        i--;
        function while_next()
        {
            i++;
            if(i<l)
            {
                return on_line(lines[i],while_next);
            }
            else
            {
                buffer.push(lines.pop());
                lines.length=0;
                return readStream.resume();
            }
        }
        while_next();
    });
  }).on('end', ()=>{
      if(buffer.length)
          var str=buffer.join('');
          buffer.length=0;
        on_line(str,()=>{
            ////after end
            console.error('done')
            ////end after end
        });
  });
readStream.resume();

-1

Benim durumumda program (elinks) boş görünen, ama aslında özel terminal karakterleri, renk kontrol kodları ve geri alanı olan satırlar döndürdü, bu yüzden grepdiğer cevaplarda sunulan seçenekler benim için işe yaramadı. Bu küçük betiği Node.js'de yazdım. Dosyayı aradım tight, ama bu sadece rastgele bir isim.

#!/usr/bin/env node

function visible(a) {
    var R  =  ''
    for (var i = 0; i < a.length; i++) {
        if (a[i] == '\b') {  R -= 1; continue; }  
        if (a[i] == '\u001b') {
            while (a[i] != 'm' && i < a.length) i++
            if (a[i] == undefined) break
        }
        else R += a[i]
    }
    return  R
}

function empty(a) {
    a = visible(a)
    for (var i = 0; i < a.length; i++) {
        if (a[i] != ' ') return false
    }
    return  true
}

var readline = require('readline')
var rl = readline.createInterface({ input: process.stdin, output: process.stdout, terminal: false })

rl.on('line', function(line) {
    if (!empty(line)) console.log(line) 
})
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.