대화식으로 콘솔에서 가치를 읽습니다.


155

콘솔 확장 기능을 가진 간단한 서버 http 서버를 만들려고 생각했습니다. 명령 줄 데이터에서 읽을 스 니펫을 찾았습니다.

  var i = rl.createInterface(process.stdin, process.stdout, null);
  i.question('Write your name: ', function(answer) {
    console.log('Nice to meet you> ' + answer);
    i.close();
    process.stdin.destroy();

  });

반복적으로 질문을하려면 while(done) { }루프 를 사용할 수 없습니까? 또한 서버가 질문 시간에 출력을 받으면 회선을 망칩니다.


5
나는 rl당신이 readline 을 의미 한다고 가정 합니까?
jpaugh

이 답변에 사용 된 것과 같은 비 차단 인터페이스를 사용 하면 while(done)루프를 수행 할 수 있습니다 .
Keyvan

답변:


182

"while (done)"루프를 수행 할 수 없습니다. 입력을 차단해야하기 때문입니다. node.js는 원하지 않습니다.

대신 무언가를 입력 할 때마다 호출되도록 콜백을 설정하십시오.

var stdin = process.openStdin();

stdin.addListener("data", function(d) {
    // note:  d is an object, and when converted to a string it will
    // end with a linefeed.  so we (rather crudely) account for that  
    // with toString() and then trim() 
    console.log("you entered: [" + 
        d.toString().trim() + "]");
  });

2
이 작업에 감사드립니다. "end"리스너는 일부 종료 작업을 호출하고 'Goodbye'라고 말합니까?
Risto Novik

예제에서 "end"리스너를 제거했습니다. 정직한 것이 어디에 유용한 지 모르겠습니다.
rob

2
문자열 출력을 d.toString (). trim ()으로 단순화 할 수 있습니다.
MKN Web Solutions 19

6
이 답변은 2011 년 날짜이며 이후 많은 부분이 변경되었습니다. 특히, 대답의 첫 번째 부분은 while 루프를 수행 할 수 없다는 것입니다 ... 더 이상 유지하지 않습니다. 예, async-await 패턴으로 인해 while 루프를 사용할 수 있으며 여전히 차단되지 않습니다. 다른 답변은 그것을 반영합니다. 요즘 읽는 사람이라면 다른 답변도 참조하십시오.
Wiktor Zychla

1
@WiktorZychla를 따르기 위해 process.openStdin 함수는 여전히 작동하는 동안 2011 년경에 더 이상 사용되지 않으며 관련 문서를 찾을 수 없습니다.
calder.ty

111

이 목적으로 다른 API를 사용했습니다 ..

var readline = require('readline');
var rl = readline.createInterface(process.stdin, process.stdout);
rl.setPrompt('guess> ');
rl.prompt();
rl.on('line', function(line) {
    if (line === "right") rl.close();
    rl.prompt();
}).on('close',function(){
    process.exit(0);
});

이렇게하면 대답이가 될 때까지 루프에서 프롬프트 할 수 있습니다 right. 또한 멋진 작은 콘솔을 제공합니다. 자세한 내용은 http://nodejs.org/api/readline.html#readline_example_tiny_cli를 참조하십시오.


11
이것은 좋은 대답입니다. 명확하지 않을 수도 있지만 큰 이점은 readline이 외부 종속성이 아니라는 것입니다. node.js의 일부입니다.
jlh

51

Readline API는 12 '부터 상당히 변경되었습니다. 이 문서는 표준 스트림에서 사용자 입력을 캡처하는 유용한 예를 보여줍니다.

const readline = require('readline');

const rl = readline.createInterface({
  input: process.stdin,
  output: process.stdout
});

rl.question('What do you think of Node.js? ', (answer) => {
  console.log('Thank you for your valuable feedback:', answer);
  rl.close();
});

자세한 내용은 여기를 참조하십시오.


5
이것은 기본적인 예일뿐입니다. 당신은 어떻게 상호 작용합니까? 질문 답변? 여러 선택 등? 어떤 논리를 포함하여 사용자와 상호 작용하기 위해 열린 rl로 작업 할 수 없다면 rl을 닫은 후 다시 여는 방법
Pawel Cioch

28

나는 async-await노드> = 7.x가 사용된다고 가정하면 이것이 현대의 대답 이 필요하다고 생각합니다 .

대답은 여전히 ​​사용 ReadLine::question하지만 랩을 while (done) {}가능하게하여 OP가 명시 적으로 요구하는 것입니다.

var cl = readln.createInterface( process.stdin, process.stdout );
var question = function(q) {
    return new Promise( (res, rej) => {
        cl.question( q, answer => {
            res(answer);
        })
    });
};

그런 다음 사용법 예

(async function main() {
    var answer;
    while ( answer != 'yes' ) {
        answer = await question('Are you sure? ');
    }
    console.log( 'finally you are sure!');
})();

대화를 따라 가다

Are you sure? no
Are you sure? no
Are you sure? yes
finally you are sure!

이것은 내가 찾던 정답입니다. 나는 그것이 최고라고 생각합니다.
William Chou

아름다운. 더 큰 스크립트에는 비동기 대기가 필요합니다. 이것이 바로 내가 필요한 것입니다.
Abhay Shiro

25

사용하십시오 readline에 동기화를 , 이것은 당신이 동기 콘솔 withouts 콜백의 지옥 작업을 할 수 있습니다. 비밀번호로도 작동합니다.

var favFood = read.question('What is your favorite food? ', {
  hideEchoBack: true // The typed text on screen is hidden by `*` (default). 
});


5
이것은 추가적인 의존성이 필요하므로 다른 솔루션을 선호합니다.
Risto Novik

"Uncaught ReferenceError : read is not defined"에서 실행되지 않음
awwsmm

12

@ rob 답변은 대부분 작동하지만 긴 입력으로 예상대로 작동하지 않을 수 있습니다.

이것이 대신 사용해야하는 것입니다.

const stdin = process.openStdin();
let content = '';

stdin.addListener('data', d => {
  content += d.toString();
});

stdin.addListener('end', () => {
  console.info(`Input: ${content}`);
});

이 솔루션이 작동하는 이유에 대한 설명 :

addListener('data') 버퍼처럼 작동하면 콜백이 가득 차거나 입력이 끝나면 콜백이 호출됩니다.

긴 입력은 어떻습니까? 단일 'data'콜백으로는 충분하지 않으므로 입력을 두 개 이상의 부분으로 나눌 수 있습니다. 그것은 종종 편리하지 않습니다.

addListener('end')stdin 리더가 입력을 읽었을 때 알려줍니다. 이전 데이터를 저장 했으므로 이제 모두 함께 읽고 처리 할 수 ​​있습니다.


3
위의 코드를 사용하고 입력을 입력 한 다음 "입력"키를 누르면 콘솔에서 계속 입력을 요구합니다. 어떻게 끝내야합니까?
Matan Tubul

5

일반적인 대화 형 명령 줄 사용자 인터페이스 모음을 제공하므로 Inquirer를 사용하는 것이 좋습니다 .

const inquirer = require('inquirer');

const questions = [{
  type: 'input',
  name: 'name',
  message: "What's your name?",
}];

const answers = await inquirer.prompt(questions);
console.log(answers);

5

예를 들면 다음과 같습니다.

const stdin = process.openStdin()

process.stdout.write('Enter name: ')

stdin.addListener('data', text => {
  const name = text.toString().trim()
  console.log('Your name is: ' + name)

  stdin.pause() // stop reading
})

산출:

Enter name: bob
Your name is: bob

좋은 대답 형제! 간단하고 명확합니다.
MD.JULHAS HOSSAIN

3

이것은 너무 복잡하다. 더 쉬운 버전 :

var rl = require('readline');
rl.createInterface... etc

사용하는 것

var rl = require('readline-sync');

당신이 사용할 때 기다립니다

rl.question('string');

반복하는 것이 더 쉽습니다. 예를 들면 다음과 같습니다.

var rl = require('readline-sync');
for(let i=0;i<10;i++) {
    var ans = rl.question('What\'s your favourite food?');
    console.log('I like '+ans+' too!');
}

2

일반적인 사용 사례는 아마도 앱이 일반 프롬프트를 표시하고 switch 문에서 처리하는 것입니다.

콜백에서 자신을 호출하는 도우미 함수를 사용하면 while 루프와 동등한 동작을 얻을 수 있습니다.

const readline = require('readline');
const rl = readline.createInterface(process.stdin, process.stdout);

function promptInput (prompt, handler)
{
    rl.question(prompt, input =>
    {
        if (handler(input) !== false)
        {
            promptInput(prompt, handler);
        }
        else
        {
            rl.close();
        }
    });
}

promptInput('app> ', input =>
{
    switch (input)
    {
        case 'my command':
            // handle this command
            break;
        case 'exit':
            console.log('Bye!');
            return false;
    }
});

'app> '앱이 이미이 루프 외부의 화면에 무언가를 인쇄 하는 경우 대신 빈 문자열을 전달할 수 있습니다.


2

이것에 대한 나의 접근 방식은 비동기 생성기 를 사용하는 것 입니다.

여러 가지 질문이 있다고 가정합니다.

 const questions = [
        "How are you today ?",
        "What are you working on ?",
        "What do you think of async generators ?",
    ]

await키워드 를 사용하려면 프로그램을 비동기 IIFE로 래핑해야합니다.

(async () => {

    questions[Symbol.asyncIterator] = async function * () {
        const stdin = process.openStdin()

        for (const q of this) {
            // The promise won't be solved until you type something
            const res = await new Promise((resolve, reject) => {
                console.log(q)

                stdin.addListener('data', data => {
                    resolve(data.toString())
                    reject('err')
                });
            })

            yield [q, res];
        }

    };

    for await (const res of questions) {
        console.log(res)
    }

    process.exit(0)
})();

예상 결과 :

How are you today ?
good
[ 'How are you today ?', 'good\n' ]
What are you working on ?
:)
[ 'What are you working on ?', ':)\n' ]
What do you think about async generators ?
awesome
[ 'What do you think about async generators ?', 'awesome\n' ]

질문에 대한 답변을 모두 얻으려면 간단한 수정으로이를 달성 할 수 있습니다.

const questionsAndAnswers = [];

    for await (const res of questions) {
        // console.log(res)
        questionsAndAnswers.push(res)
    }

    console.log(questionsAndAnswers)

   /*
     [ [ 'How are you today ?', 'good\n' ],
     [ 'What are you working on ?', ':)\n' ],
     [ 'What do you think about async generators ?', 'awesome\n' ] ]
   */

2

커맨드 라인에서 입력을받는 "tic-tac-toe"게임을 Node에 작성하고 트릭을 수행하는이 기본 비동기 / 대기 코드 블록을 작성했습니다.

const readline = require('readline')

const rl = readline.createInterface({
  input: process.stdin,
  output: process.stdout
});

async function getAnswer (prompt) {
  const answer = await new Promise((resolve, reject) =>{
    rl.question(`${prompt}\n`, (answer) => {
      resolve(answer)
    });
  })
  return answer
}

let done = false
const playGame = async () => {
  let i = 1
  let prompt = `Question #${i}, enter "q" to quit`
  while (!done) {
    i += 1
    const answer = await getAnswer(prompt)
    console.log(`${answer}`)
    prompt = processAnswer(answer, i)
  }
  rl.close()
}

const processAnswer = (answer, i) => {
  // this will be set depending on the answer
  let prompt = `Question #${i}, enter "q" to quit`
  // if answer === 'q', then quit
  if (answer === 'q') {
    console.log('User entered q to quit')
    done = true
    return
  }
  // parse answer

  // if answer is invalid, return new prompt to reenter

  // if answer is valid, process next move

  // create next prompt
  return prompt
}

playGame()

1

readline 차단되지 않은 동작 차단

readline 표준 모듈에 '차단 해제'동작이 있기 때문에이 코드가 실행되지 않는다는 것을 알았으므로 콘솔에서 세 가지 질문에 대한 답변이 있다고 상상해보십시오. 각 rl.question은 독립적 인 스레드 이므로이 코드는 실행되지 않습니다.

'use strict';

var questionaire=[['First Question: ',''],['Second Question: ',''],['Third Question: ','']];

function askaquestion(question) {
const readline = require('readline');

const rl = readline.createInterface(
    {input: process.stdin, output:process.stdout}
    );
  rl.question(question[0], function(answer) {
    console.log(answer);
    question[1] = answer;
    rl.close();
  });
};

var i=0;  
for (i=0; i < questionaire.length; i++) {
askaquestion(questionaire[i]);
}

console.log('Results:',questionaire );

출력을 실행 :

node test.js
Third Question: Results: [ [ 'First Question: ', '' ],
  [ 'Second Question: ', '' ],
  [ 'Third Question: ', '' ] ]        <--- the last question remain unoverwritten and then the final line of the program is shown as the threads were running waiting for answers (see below)
aaa        <--- I responded with a single 'a' that was sweeped by 3 running threads
a        <--- Response of one thread

a        <--- Response of another thread

a        <--- Response of another thread (there is no order on threads exit)

제안 된 솔루션은 이벤트 이미 터를 사용하여 차단 해제 스레드의 끝을 알리고 루프 로직과 프로그램 끝을 해당 리스너 함수에 포함시킵니다.

'use strict';

var questionaire=[['First Question: ',''],['Second Question: ',''],['Third Question: ','']];

// Introduce EventEmitter object
const EventEmitter = require('events');

class MyEmitter extends EventEmitter {};

const myEmitter = new MyEmitter();
myEmitter.on('continue', () => {
  console.log('continue...');
  i++; if (i< questionaire.length) askaquestion(questionaire[i],myEmitter);    // add here relevant loop logic
           else console.log('end of loop!\nResults:',questionaire );
});
//

function askaquestion(p_question,p_my_Emitter) { // add a parameter to include my_Emitter
const readline = require('readline');

const rl = readline.createInterface(
    {input: process.stdin, output:process.stdout}
    );
  rl.question(p_question[0], function(answer) {
    console.log(answer);
    p_question[1] = answer;
    rl.close();
    myEmitter.emit('continue');    // Emit 'continue' event after the question was responded (detect end of unblocking thread)
  });
};

/*var i=0;  
for (i=0; i < questionaire.length; i++) {
askaquestion(questionaire[i],myEmitter);
}*/

var i=0;
askaquestion(questionaire[0],myEmitter);        // entry point to the blocking loop


// console.log('Results:',questionaire )    <- moved to the truly end of the program

출력을 실행 :

node test2.js
First Question: 1
1
continue...
Second Question: 2
2
continue...
Third Question: 3
3
continue...
done!
Results: [ [ 'First Question: ', '1' ],
  [ 'Second Question: ', '2' ],
  [ 'Third Question: ', '3' ] ]

0

나는 디렉토리를 읽기위한 작은 스크립트를 만들고 콘솔 이름 새 파일 (예 : 'name.txt')과 텍스트를 파일에 씁니다.

const readline = require('readline');
const fs = require('fs');

const pathFile = fs.readdirSync('.');

const file = readline.createInterface({
  input: process.stdin,
  output: process.stdout
});

file.question('Insert name of your file? ', (f) => {
  console.log('File is: ',f.toString().trim());
  try{
    file.question('Insert text of your file? ', (d) => {
      console.log('Text is: ',d.toString().trim());
      try {
        if(f != ''){
          if (fs.existsSync(f)) {
            //file exists
            console.log('file exist');
            return file.close();
          }else{
            //save file
            fs.writeFile(f, d, (err) => {
                if (err) throw err;
                console.log('The file has been saved!');
                file.close();
            });
          }
        }else{
          //file empty 
          console.log('Not file is created!');
          console.log(pathFile);
          file.close();
        }
      } catch(err) {
        console.error(err);
        file.close();
      }
    });
  }catch(err){
    console.log(err);
    file.close();
  }
});

0

가장 쉬운 방법은 readline-sync를 사용하는 것입니다

입력과 출력을 하나씩 처리합니다.

npm i readline-sync

예 :

var firstPrompt = readlineSync.question('Are you sure want to initialize new db? This will drop whole database and create new one, Enter: (yes/no) ');

if (firstPrompt === 'yes') {
    console.log('--firstPrompt--', firstPrompt)
    startProcess()
} else if (firstPrompt === 'no') {
    var secondPrompt = readlineSync.question('Do you want to modify migration?, Enter: (yes/no) ');
    console.log('secondPrompt ', secondPrompt)
    startAnother()
} else {
    console.log('Invalid Input')
    process.exit(0)
}

당신은 정말 당신의 require진술을 포함해야 합니다. 그것을 버릴 이유가 없습니다.
solidstatejake
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.