以交互方式从控制台读取价值

时间:2011-11-14 21:42:03

标签: node.js console

我想用一些控制台扩展来创建一个简单的服务器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) { }循环?如果服务器在提问时接收输出也很好,它会破坏该行。

16 个答案:

答案 0 :(得分:155)

你不能做“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() + "]");
  });

答案 1 :(得分:99)

为此,我使用了另一个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

答案 2 :(得分:41)

自12'以来,Readline API发生了很大的变化。该文档显示了从标准流中捕获用户输入的有用示例:

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

More information here.

答案 3 :(得分:19)

请使用readline-sync,这样您就可以使用同步控制台而无需回调地狱。甚至可以使用密码:



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




答案 4 :(得分:12)

@rob answer在大多数情况下都会起作用,但它可能不会像你期望的那样长时间输入。

这就是你应该使用的东西:

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

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

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

解释此解决方案的工作原理:

addListener('data')的工作方式类似于缓冲区,回调将在满或/或其输入结束时被调用。

长输入怎么样?单个'data'回调是不够的,因此您可以将输入拆分为两个或多个部分。这通常不方便。

当stdin阅读器完成阅读我们的输入时,

addListener('end')会通知我们。由于我们一直存储以前的数据,现在我们可以一起读取和处理它们。

答案 5 :(得分:12)

我认为这应该得到一个现代的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!

答案 6 :(得分:4)

我建议使用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);

答案 7 :(得分: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> '

答案 8 :(得分:1)

阻止readline阻止行为

想象一下,您有三个问题要从控制台中回答,因为您现在知道该代码将无法运行,因为readline标准模块具有“不受阻碍”的行为,因此每个rl.question是一个独立线程,因此该代码将不会运行。 / p>

'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' ] ]

答案 9 :(得分:1)

这是一个例子:

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

答案 10 :(得分:1)

阻止readline畅通无阻的行为/带有承诺的替代解决方案

想象一下,您有三个问题要从控制台中回答,因为您现在知道该代码将无法运行,因为readline标准模块具有“不受阻碍”的行为,因此每个rl.question是一个独立线程,因此该代码将不会运行。 / p>

'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)

*建议的解决方案使用Promises,因此仅当我们对第一个问题有答复时,才处理第二个问题,依此类推。

'use strict';

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

function askaquestion(p_questionaire,p_i) {
p_questionaire[p_i][1] = new Promise(function (resolve,reject){ 
const readline = require('readline');

const rl = readline.createInterface(
    {input: process.stdin, output:process.stdout}
    );
rl.question(p_questionaire[p_i][0], function(answer) {
    //console.log(answer);
    resolve(answer),reject('error');
    rl.close();
    });
});
p_questionaire[p_i][1].then(resolve=>{
    if (p_i<p_questionaire.length-1) askaquestion(p_questionaire,p_i+1);
    else console.log('Results: ',p_questionaire) });
};

askaquestion(questionaire,0);

运行输出:

>node test3.js
First Question: 1
Second Question: 2
Third Question: 3
Results:  [ [ 'First Question: ', Promise { '1' } ],
  [ 'Second Question: ', Promise { '2' } ],
  [ 'Third Question: ', Promise { '3' } ] ]

答案 11 :(得分:1)

我的解决方法是使用异步生成器

假设您有一系列问题:

 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' ] ]
   */

答案 12 :(得分:1)

我创建了一个小脚本来读取目录,并将控制台名称新文件(例如:'name.txt')写入文本。

GameObject newAnimal = Instantiate(ListItemPrefab) as GameObject;
ListItemController controller = newAnimal.GetComponent();

答案 13 :(得分:1)

这太复杂了。一个更简单的版本:

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

答案 14 :(得分:1)

我必须在Node中编写一个“井字游戏”,该游戏从命令行获取输入,并编写了完成该操作的基本async / await代码块。

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()

答案 15 :(得分: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)
}