Node.js에서 사용자 입력을 읽으려면 process.stdin에 readline 인터페이스를 만들고 rl.question()으로 묻습니다. Node.js에는 prompt()가 없습니다. 브라우저 버전은 대화 상자를 여는데, 터미널 프로그램에는 대화 상자가 없기 때문입니다. 요즘 방식은 readline/promises를 쓰는 것으로, await rl.question('Name? ')이 사용자가 입력한 줄을 반환합니다. 다 쓰면 인터페이스를 닫으세요. 그러지 않으면 프로그램이 입력을 계속 기다립니다.
question()이 프롬프트를 출력하고, 입력 한 줄을 기다린 다음 줄바꿈을 뺀 문자열을 반환했습니다. 그래서 프로그램이 Next year you will be 37.을 출력했습니다. 질문이 여러 개라면 question()을 하나씩 차례로 await하세요.
콜백을 쓰는 readline question()
모든 Node.js 버전에 있는 원래 API는 답을 콜백에 넘깁니다. 질문을 이어 가면 콜백도 중첩됩니다.
프롬프트가 출력된 뒤 You picked blue.가 출력되었습니다. 답은 평범한 문자열이므로 비교하기 전에 trim하세요. 단어 뒤에 공백을 친 사용자의 답은 'blue '가 되어 'blue'와 같지 않습니다.
한 줄씩 입력 읽기
입력이 끝날 때까지 모든 줄을 처리하려면 인터페이스를 for await로 순회합니다. 사용자가 입력하는 목록(Ctrl+D로 끝냄)이나 node index.js < numbers.txt로 파이프한 파일을 이렇게 읽습니다. 예전 코드는 같은 일을 이벤트로 합니다. 줄마다 rl.on('line', fn), 끝에서 rl.on('close', fn)입니다. 이 반복문은 그 두 이벤트를 위에서 아래로 쓴 것입니다.
3 numbers, total 49가 출력되었고, 입력이 끝나자 반복문이 저절로 끝났으므로 close()는 필요 없습니다. 네 번째 입력 줄로 1을 추가하면 결과는 4 numbers, total 50이 됩니다.
stdin을 한 번에 모두 읽기
다른 프로그램에서 파이프로 들어오는 입력(cat data.txt | node index.js)이라면 한 번의 호출로 전부 읽는 편이 간단합니다. 파일 디스크립터 0이 표준 입력입니다. 윈도우에서 저장한 파일은 줄 끝이 \r\n일 수 있으니, 그런 입력이 올 수 있다면 /\r?\n/로 나누세요.
세 항목이 열을 맞춰 출력되었습니다. readFileSync(0)은 입력이 끝날 때까지 막힙니다. 파이프를 읽는 스크립트나 테스트에는 괜찮지만, 대화형 도구에는 맞지 않습니다. 사용자가 프롬프트를 하나도 보기 전에 모든 것을 입력해야 하기 때문입니다.
무엇을 쓸까
네 가지 모두 같은 표준 입력을 읽습니다. 다른 점은 코드가 텍스트를 받는 시점입니다. 답 하나씩, 줄 하나씩, 또는 마지막에 전부 받습니다.
| 필요한 것 | 쓸 것 |
|---|---|
| 질문 몇 개를 순서대로 묻기 | readline/promises와 await rl.question() |
| 17 이전 Node.js 버전 지원 | readline과 question() 콜백 |
| 들어오는 줄을 하나씩 처리 | for await (const line of rl) |
| 파이프나 파일 전체를 stdin에서 읽기 | fs.readFileSync(0, 'utf8') |
| 프로그램 시작 전에 아는 값 | 대신 process.argv |
흔한 실수
rl.close()를 잊는 것. 인터페이스가 표준 입력을 열어 두기 때문에 마지막 질문 뒤에도 프로그램이 끝나지 않습니다. 답을 다 받으면 닫으세요.
답을 숫자처럼 쓰는 것. 터미널에서 입력한 모든 것처럼 답은 문자열입니다. '36' + 1은 '361'이니 먼저 Number()로 바꾸세요.
여러 답을 파이프로 여러 질문에 흘려보내는 것. 입력이 키보드가 아니라 파이프에서 오면 readline은 전부를 한 번에 읽고, 해당 question()이 묻기 전에 도착한 줄은 버려집니다. 파이프 입력에는 for await 반복문이나 readFileSync(0)을 쓰세요.
output 옵션을 빼는 것. output: process.stdout이 없으면 question()이 프롬프트를 출력하지 않아서 사용자는 빈 터미널만 보게 됩니다. 한 줄씩 읽는 반복문은 아무것도 출력하지 않으므로 이 옵션이 필요 없습니다.
자주 묻는 질문
Node.js에서 prompt가 정의되지 않았다고 나오는 이유는?
prompt()는 대화 상자를 여는 브라우저 함수인데, Node.js에는 그걸 열 창이 없습니다. Node.js에서는 readline을 쓰거나, 메뉴나 비밀번호 입력이 필요하면 prompts, inquirer 같은 패키지를 쓰세요.
비밀번호를 화면에 보이지 않게 읽으려면?
readline은 누른 키를 모두 화면에 보여 줍니다. prompts나 @inquirer/password 같은 패키지는 입력을 가려 줍니다. 직접 하려면 process.stdin.setRawMode(true)로 터미널을 raw 모드로 바꾸고 키를 하나씩 처리해야 합니다.
readline과 process.argv 중 무엇을 써야 하나요?
값을 프로그램 시작 전에 알 수 있다면 process.argv를 쓰세요. 사람이 없어도 스크립트에서 실행할 수 있습니다. 질문을 하나씩 이어서 묻는 대화형 도구에는 readline을 쓰세요.