Konsoldan değeri okuma, etkileşimli


155

Bazı konsol uzantısı ile basit bir sunucu http sunucusu yapmayı düşündüm. Parçacığı komut satırı verilerinden okumak için buldum.

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

  });

tekrar tekrar soru sormak için, ben sadece while(done) { }döngü kullanamazsınız ? Ayrıca sunucu soru zamanında çıktı alırsa, hattı bozar.


5
Ben tarafından varsayalım rlortalama size taleb ?
jpaugh

Bu yanıtta kullanılana benzer bir engelleme olmayan arabirim kullanabilirsiniz , sonra bir while(done)döngü yapabilirsiniz .
Keyvan

Yanıtlar:


182

bir "while (done)" döngüsü yapamazsınız, çünkü bu girişte engelleme gerektirir, node.js'nin yapmak istemediği bir şeydir.

Bunun yerine, her şey girildiğinde çağrılacak bir geri arama ayarlayın:

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
Teşekkür ederim bu çalışır, "son" dinleyici bazı kapanış işlemleri çağırmak ve 'veda' demek için izin veriyor mu?
Risto Novik

"End" dinleyicisini örnekten kaldırdım, dürüst olmanın gerçekten yararlı olacağını bilmiyorum.
soymak

2
Dize çıktısını d.toString (). Trim () 'e basitleştirebilirsiniz
MKN Web Solutions

6
Bu cevap 2011 tarihlidir ve o zamandan beri çok şey değişmiştir. Özellikle, cevabın ilk kısmı, bir while döngüsü yapamazsınız ... artık tutmuyor. Evet, async-await modeli sayesinde bir while döngünüz olabilir ve yine de engellemeyebilirsiniz. Diğer cevaplar bunu yansıtıyor. Bugünlerde bunu okuyan herkese - lütfen diğer cevaplara da bakın.
Wiktor Zychla

1
@WiktorZychla'yı takip etmek için, hala çalışırken process.openStdin işlevi 2011 yılı civarında kullanımdan kaldırıldı ve bununla ilgili herhangi bir belge bulamayacaksınız.
calder.ty

112

Bu amaçla başka bir API kullandım.

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

Bu, yanıt verilene kadar döngüde bilgi istemine izin verir right. Ayrıca güzel küçük bir konsol verir.Ayrıntıları @ http://nodejs.org/api/readline.html#readline_example_tiny_cli bulabilirsiniz


11
Bu harika bir cevap. Açık olmayan şey olabilir (ancak büyük bir artıdır) readline'ın dışa bağımlılık olmaması: node.js'nin bir parçasıdır.
jlh

51

Readline API'sı 12 'den bu yana biraz değişti. Dokümanlar, standart bir akıştan kullanıcı girişini yakalamak için yararlı bir örnek gösterir:

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

Daha fazla bilgi burada.


5
bu sadece temel bir örnek. Nasıl etkileşime giriyorsun? soru cevap? birden fazla seçenek ve benzeri? Bir kez kapatıldığında rl nasıl yeniden açılır, eğer bazı mantık da dahil olmak üzere kullanıcıyla etkileşim kurmak için açık rl ile nasıl çalışılamazsa
Pawel Cioch

28

async-awaitDüğümün = = 7.x kullanıldığı varsayılarak, bunun modern bir cevabı hak ettiğine inanıyorum .

Cevap hala kullanıyor ReadLine::questionancak sarar, böylece while (done) {}OP, açık bir şekilde sorduğu bir şeydir.

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

ve sonra örnek bir kullanım

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

aşağıdaki konuşmaya yol açar

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

Aradığım cevap tam olarak buydu. Bence en iyisi olmalı.
William Chou

Güzel. Daha büyük komut dosyaları için zaman uyumsuz beklemeniz gerekir. Tam da ihtiyacım olan şey bu.
Abhay Shiro

25

Lütfen readline-sync kullanın , bu, geri çağırma cehennemleri olmadan senkron konsolla çalışmanıza izin verir. Parolalarla bile çalışır:

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


5
Bu ekstra bağımlılık gerektirir, bu yüzden diğer çözümleri tercih ederim.
Risto Novik


12

@rob yanıtı çoğu zaman çalışır, ancak uzun girdilerden beklediğiniz gibi çalışmayabilir.

Bunun yerine kullanmanız gereken şey budur:

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

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

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

Bu çözümün neden çalıştığına ilişkin açıklama:

addListener('data') bir arabellek gibi çalışır, dolu olduğunda geri arama çağrılır ve / ve giriş sonu olur.

Uzun girdiler ne olacak? Tek bir 'data'geri arama yeterli olmaz, bu nedenle girişinizi iki veya daha fazla parçaya bölebilirsiniz. Bu genellikle uygun değildir.

addListener('end')stdin okuyucusu girdimizi okuduktan sonra bize bildirecektir. Önceki verileri sakladığımızdan, artık hepsini birlikte okuyabilir ve işleyebiliriz.


3
Ben yukarıdaki kodu kullanırken ve bazı giriş eklemek ve sonra "enter" tuşuna konsol daha fazla giriş için bana sormaya devam. nasıl feshedebiliriz?
Matan Tubul

5

Ortak etkileşimli komut satırı kullanıcı arabirimleri koleksiyonu sağladığı için Inquirer'ı kullanmanızı öneririm .

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

İşte bir örnek:

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

Çıktı:

Enter name: bob
Your name is: bob

Güzel cevap kardeşim !! Sadece basit ve net.
MD.JULHAS HOSSAIN

3

Bu çok karmaşık. Daha kolay bir sürümü:

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

kullanmak olurdu

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

o zaman kullandığında bekleyecek

rl.question('string');

o zaman tekrarlamak daha kolaydır. Örneğin:

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

Yaygın bir kullanım durumu, uygulamanın genel bir istem görüntülemesi ve bir switch deyiminde işlemesi olabilir.

Geri aramada kendisini çağıracak bir yardımcı işlev kullanarak while döngüsüne eşdeğer bir davranış elde edebilirsiniz:

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> 'Uygulamanız ekrana bu döngünün dışında bir şey yazdırıyorsa boş bir dize geçirebilirsiniz .


2

Buna yaklaşımım, zaman uyumsuz üreteçler kullanmak olacaktır .

Bir dizi sorunuz olduğunu varsayarsak:

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

awaitAnahtar kelimeyi kullanabilmek için programınızı zaman uyumsuz IIFE'ye sarmanız gerekir.

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

Beklenen sonuçlar:

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

Soruları tamamen cevaplamak istiyorsanız, bunu basit bir değişiklikle başarabilirsiniz:

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

Düğümde komut satırından girdi aldı ve hile yaptı bu temel asenkron / bekliyor kod bloğunu yazdı bir "tic-tac-toe" oyunu yazmak zorunda kaldı.

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'ın engellenmemiş davranışını engelleme

Konsoldan yanıtlanacak üç sorunuz olduğunu düşünün, çünkü artık bu kodun çalışmayacağını bildiğiniz için readline standart modülünün 'engellenmemiş' davranışı vardır, her rl.question bağımsız bir iş parçacığıdır, bu nedenle bu kod çalışmaz.

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

Koşu çıkışı:

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)

Önerilen çözüm, blokaj açma iş parçacığının sonunu bildirmek için bir olay yayıcı kullanır ve döngü mantığını ve programın sonunu dinleyici işlevine dahil eder.

'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

Koşu çıkışı:

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

Ben okuma dizini için küçük bir komut dosyası ve bir konsol adı yeni dosya (örnek: 'name.txt') ve dosyaya metin yazmak var.

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

En kolay yol readline-sync kullanmaktır

Birer birer giriş ve çıkış işlemi yapar.

npm i readline-sync

Örneğin:

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

İfadenizi gerçekten eklemelisiniz require. Dışarıda bırakmak için bir neden yok.
solidstatejake
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.