92

I have just started using Node.js, and I don't know how to get user input. I am looking for the JavaScript counterpart of the python function input() or the C function gets. Thanks.

4

9 Answers 9

110

There are 4 options you could use. I will walk you through these examples:

(Option 1) readline (async/await): In my opinion, it is the best option as we can get the user input asynchronously using async/await in Node.js. You need to wrap the rl.question method in a promise to make it work with async/await..

const readline = require('readline');

// Create an interface for input and output
const rl = readline.createInterface({
  input: process.stdin,
  output: process.stdout
});

const askQuestion = (question) => {
  return new Promise((resolve) => {
    rl.question(question, (answer) => {
      resolve(answer);
    });
  });
};

// Main async function
const main = async () => {
  // Get user input using await
  const name = await askQuestion('What is your name? ');

  // Print the result
  console.log(`Hello, ${name}!`);

  // Close the readline interface
  rl.close();
};

// Call the main async function
main();

(Option 2) prompt-sync: It is a module available on npm and you can refer to the docs for more examples prompt-sync.

npm install prompt-sync
const prompt = require("prompt-sync")({ sigint: true });
const age = prompt("How old are you? ");
console.log(`You are ${age} years old.`);

(Option 3) prompt: It is another module available on npm:

npm install prompt
const prompt = require('prompt');

prompt.start();

prompt.get(['username', 'email'], function (err, result) {
    if (err) { return onErr(err); }
    console.log('Command-line input received:');
    console.log('  Username: ' + result.username);
    console.log('  Email: ' + result.email);
});

function onErr(err) {
    console.log(err);
    return 1;
}

(Option 4) readline (callbacks): Another example with readline but using callbacks:

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

rl.question("What is your name ? ", function(name) {
    rl.question("Where do you live ? ", function(country) {
        console.log(`${name}, is a citizen of ${country}`);
        rl.close();
    });
});

rl.on("close", function() {
    console.log("\nBYE BYE !!!");
    process.exit(0);
});
Sign up to request clarification or add additional context in comments.

Comments

63

This can also be done natively with promises. It is also more secure then using outside world npm modules. No longer need to use callback syntax.

Updated answer from @Willian. This will work with async/await syntax and ES6/ES7.

const readline = require('readline');

const rl = readline.createInterface({ input: process.stdin, output: process.stdout });
const prompt = (query) => new Promise((resolve) => rl.question(query, resolve));

// Usage inside aync function do not need closure demo only
(async() => {
  try {
    const name = await prompt("What's your name: ");
    // Can use name for next question if needed
    const lastName = await prompt(`Hello ${name}, what's your last name?: `);
    // Can prompt multiple times
    console.log(name, lastName);
    rl.close();
  } catch (e) {
    console.error("Unable to prompt", e);
  }
})();

// When done reading prompt, exit program 
rl.on('close', () => process.exit(0));

6 Comments

just tested: putting the rl declaration (ine 3) inside the async-function ensures, that it goes out of scopes, no need for your very last line then.
This is the best answer.
How can I make an outer program wait until I've collected all my input? I'm trying to store it and use it, not just print it.
You can use the readline/promises module for the async/await syntax.
Note that as of Jan 2023, the readline/promises API is considered level 1 - experimental Non-backward compatible changes or removal may occur in any future release. Use of the feature is not recommended in production environments. – KyleMit ♦ Jan 7 at
|
22

If you want to use ESM (import instead of require):

import * as readline from 'node:readline/promises';  // This uses the promise-based APIs
import { stdin as input, stdout as output } from 'node:process';

const rl = readline.createInterface({ input, output });

const answer = await rl.question('What do you think of Node.js? ');

console.log(`Thank you for your valuable feedback: ${answer}`);

rl.close();

Source: https://nodejs.org/api/readline.html#readline

Note that this is a a new feature. From the source linked above, it seems like node v17.9.1 or above is required.

1 Comment

Note that as of Jan 2023, the readline/promises API is considered level 1 - experimental Non-backward compatible changes or removal may occur in any future release. Use of the feature is not recommended in production environments.
5

The other solutions here are either async, or use the blocking prompt-sync. I want a blocking solution, but prompt-sync consistently corrupts my terminal.

I found a lovely answer here which offers a good solution.

Edit: see an improved version for Linux here.

Create the function:

const prompt = msg => {
  fs.writeSync(1, String(msg));
  let s = '', buf = Buffer.alloc(1);
  while(buf[0] - 10 && buf[0] - 13)
    s += buf, fs.readSync(0, buf, 0, 1, 0);
  return s.slice(1);
};

Use it:

const result = prompt('Input something: ');
console.log('Your input was: ' + result);

Disclaimer: I'm cross-posting my own answer from here.

6 Comments

Great solution. Yet it would be much better for users if it was hidden behind a simple Node.js built-in function named perhaps console.read(). Above bit-mangling is not simple to understand nor to remember or type right every time you or somebody needs it. As said in the discussion at github.com/nodejs/node/issues/28243 if there is built-in console.log(), why isn't there built-in console.read() ?
@PanuLogic I agree. The Node dev community won't budge on this, though, and I don't get why :/. console.read() not being implemented I can understand because it pollutes the console namespace, but a global prompt() makes sense because we already mimic browsers with things like setTimeout(), so why not prompt() as well? Or maybe in one of the Node utils built-ins if they're concerned about new globals breaking backwards compatibility
I get an error on the readsync. "Error: ESPIPE: invalid seek, read". I got it to work by using the openSync method to open stdin first, as suggested here: stackoverflow.com/a/21132342/300213 Also, pass null as the last argument to readSync. Could be a linux thing?
@user4815162342 Seems like it - I tried in a GUI-less Ubuntu 18.04 VM now and got the same error, using Node 16.13
@aggregate1166877 To clarify: I fixed ESPIPE by passing null as the last argument to readSync instead of 0. This gave me an ESAGAIN error, which I fixed by getting the fd to pass to readSync with this statement: let stdin = fs.openSync("/dev/stdin","rs");. I suspect this is something like what readline does. I will put my complete solution in a different answer.
|
2

This also works well:

const fs = require('fs');

process.stdin.resume();
process.stdin.setEncoding('utf-8');

let inputString = '';
let currentLine = 0;

process.stdin.on('data', inputStdin => {
    inputString += inputStdin;
});

process.stdin.on('end', _ => {
    inputString = inputString.replace(/\s*$/, '')
        .split('\n')
        .map(str => str.replace(/\s*$/, ''));

    main();
});

function readLine() {
    return inputString[currentLine++];
}

function main() {
    const ws = fs.createWriteStream(process.env.OUTPUT_PATH);

    const n = parseInt(readLine(), 10); // Read and integer like this

    // Read an array like this
    const c = readLine().split(' ').map(cTemp => parseInt(cTemp, 10));

    let result; // result of some calculation as an example

    ws.write(result + "\n");

    ws.end();
}

Here my process.env.OUTPUT_PATH is set, if yours is not, you can use something else.

Comments

2

The answer from aggregate1166877 didn't work on linux, causing ESPIPE and ESAGAIN errors without two changes.

This solution fixes those:

    let stdin = fs.openSync("/dev/stdin","rs");

    const read = function(message) {
        fs.writeSync(process.stdout.fd, message + " ");
        let s = '';
        let buf = Buffer.alloc(1);
        fs.readSync(stdin,buf,0,1,null);
        while((buf[0] != 10) && (buf[0] != 13)) {
            s += buf;
            fs.readSync(stdin,buf,0,1,null);
        }
        return s;
    }

1 Comment

Very nice fix :)
1

It is a form of asynchronous input/output handling in Node.js. We used standard input and output streams to interact with the user or process input and output data. I have used it in hackerank question.

process.stdin.resume();
process.stdin.setEncoding("utf-8");
var stdin_input = "";

process.stdin.on("data", function (input) {
    stdin_input += input; // Reading input from STDIN using `data` event.
});

//the `end `event is used to know when input reading is complete.
process.stdin.on("end", function () { 
   main(stdin_input); //passing a parameter in main function
});


function main(inp){
process.stdout.write(inp);

}

Comments

1

Basically, a function like input() that exists in Python is not available in NodeJs, on the other hand, there is no clear and simple method to get data from the input.

But in general, this goal can be achieved in two ways:

  1. Using internal modules available in NodeJs.

This method requires a lot of configuration, so for someone new to NodeJs, it may be too complicated and you may not get the result you want.

  1. In the second method, it is better to use external modules (packages).

In this way, the complications of this work are minimized and you can reach this goal very easily.

For the second way, there are many packages, one of them is Softio, which has the same methods you mentioned.

To use Softio, just follow the instructions below step by step:

  1. First you need to install this package. Just run the following command in your project path:
npm install softio

There is no need to worry, when you have installed Node Js, you have also installed npm and you can run the above command.

  1. Then it is enough to write the following code to get the data from user:
const Console = require( 'softio' );

const name = Console.In.input( 'Enter your name: ' );
Console.Out.writeln( `Welcome ${name}.` );

You can easily read this data from the input like this.

Comments

0
import { createInterface } from "node:readline/promises";

async function input(prompt: string): Promise<string> {
  const rl = createInterface(process.stdin, process.stdout)
  const answ = await rl.question(prompt)
  rl.close()
  return answ
}

const name = await input("what's your name: ")

console.log("your name is", name)

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.