노드에서 stdin을 한 줄씩 읽는 방법


177

다음과 같은 명령 줄 호출을 사용하여 노드가있는 텍스트 파일을 처리하려고합니다.

node app.js < input.txt

파일의 각 줄은 개별적으로 처리해야하지만 일단 처리되면 입력 줄을 잊을 수 있습니다.

stdin의 온 데이터 리스너를 사용하여 입력 스팀을 바이트 크기로 청크하여이를 설정했습니다.

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);
});

그러나 이것은 너무 조잡 해 보입니다. 라인 배열의 첫 번째 항목과 마지막 항목을 마사지해야합니다. 더 우아한 방법이 없습니까?

답변:


207

readline 모듈을 사용하여 stdin을 한 줄씩 읽을 수 있습니다 .

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
콘솔에서 직접 입력을 입력하면 잘 작동하는 것처럼 보이지만 명령에 파일을 전달하면 파일이 stdout으로 전송됩니다. 버그? 이 시점에서 readline은 불안정한 것으로 간주됩니다.
Matt R. Wilson

1
난 당신이 바로 변경할 수 있다고 생각 process.stdout다른 쓰기 가능한 스트림 - 그것은 단순하게 될 수있다output: new require('stream').Writable()
제프 Sisson

3
불행히도, 나는 stdout이 필요합니다. 내 질문에서 제외했지만 앱을로 사용할 수있게하려고합니다 node app.js < input.txt > output.txt.
매트 R. 윌슨

분명히 이것은``설계에 의한 '' gitgit.com/joyent/node/issues/4243#issuecomment-10133900 입니다. 그래서 나는 당신이 말하고 출력 옵션에 더미 쓰기 가능 스트림을 제공 한 다음 stdout 스트림에 직접 썼습니다. 나는 그것을 좋아하지 않지만 작동합니다.
매트 R. 윌슨

13
terminal: falsecreateInterface에 인수 를 전달하면 이 문제가 해결됩니다.
jasoncrawford

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

3
세부 사항을 포함시킬 수 있습니까? 이미 높은 평가를받은 답변이 있습니다
jhhoff02

2
이것은 나를 위해 작동하지 않습니다 (노드 v9.2.0, Windows). Error: EISDIR: illegal operation on a directory, fstat at tryStatSync (fs.js : 534 : 13)`
AlexChaffee

2
노드 v6.11.2, OSX에서 나를 위해 일했습니다.
tiffon

3
@AlexChaffee : stdin 입력이 없거나 stdin이 닫히면 Windows에 버그가있는 것으로 보입니다 (여전히 v9.10.1부터 있음) . 이 GitHub 문제를 참조하십시오 . 그러나이 솔루션 Windows에서 작동합니다.
mklement0

3
아주 잘 작동하고 훨씬 짧다는 수행하여 짧게 만들 수fs.readFileSync(0).toString()
localhostdotdev

56

readline터미널과 함께 작동하도록 특별히 설계되었습니다 process.stdin.isTTY === true. 같은 일반적인 스트림에 대한 분할 기능을 제공하는 모듈이 많이 있습니다 분할 . 일이 매우 쉬워집니다.

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

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

6
아니에요 한 줄씩 읽고 싶지 않다면 전혀 필요하지 않습니다
vkurchatkin

6
팁 : 모든 행을 처리 한 후 일부 코드를 실행 .on('end', doMoreStuff)하려면 첫 번째 뒤에 추가 하십시오 .on(). with 문 다음에 코드를 정상적으로 작성하면 .on()JavaScript가 동기식이 아니기 때문에 입력을 읽기 전에 해당 코드가 실행됩니다.
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

다른 사람과 공유 :

스트림을 한 줄씩 읽으면 stdin, 내 버전으로 파이프 된 큰 파일에 적합해야합니다.

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

필자의 경우 프로그램 (elinks)은 비어있는 줄을 반환했지만 실제로 특수 터미널 문자, 색상 제어 코드 및 백 스페이스가 있었으므로 grep다른 답변에 표시된 옵션은 작동하지 않았습니다. 그래서이 작은 스크립트를 Node.js에 작성했습니다. 나는 파일을 불렀지 tight만 그것은 임의의 이름 일뿐입니다.

#!/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) 
})
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.