Чтение значения из консоли, в интерактивном режиме - PullRequest
134 голосов
/ 15 ноября 2011

Я подумал сделать простой сервер 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) { }?Также хорошо, если сервер получает выходные данные во время вопроса, это разрушает линию.

Ответы [ 14 ]

159 голосов
/ 15 ноября 2011

Вы не можете выполнить цикл 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() + "]");
  });
100 голосов
/ 01 декабря 2012

Я использовал другой 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

41 голосов
/ 24 мая 2016

API Readline сильно изменился с 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();
});

Дополнительная информация здесь.

21 голосов
/ 01 марта 2017

Пожалуйста, используйте readline-sync , это позволяет вам работать с синхронной консолью без ада обратных вызовов. Даже работает с паролями:

var favFood = read.question('What is your favorite food? ', {
  hideEchoBack: true // The typed text on screen is hidden by `*` (default). 
});
13 голосов
/ 29 сентября 2017

Я полагаю, что это заслуживает современного ответа async-await, предполагая, что используется узел> = 7.x.

В ответе по-прежнему используется ReadLine::question, но он оборачивается так, что возможен while (done) {}, о чем ОП явно спрашивает.

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!
12 голосов
/ 08 января 2017

@ 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 закончит чтение нашего ввода. Поскольку мы хранили предыдущие данные, теперь мы можем читать и обрабатывать их все вместе.

4 голосов
/ 07 ноября 2018

Я рекомендую использовать 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);
3 голосов
/ 09 апреля 2019

Это слишком сложно. Более простая версия:

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 голосов
/ 15 января 2019

Вот пример:

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
2 голосов
/ 23 января 2018

В общем случае, вероятно, приложение отображает универсальное приглашение и обрабатывает его в операторе 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> ', если ваше приложение уже что-то печатает на экране за пределами этого цикла.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...