Как child_process.exec('powershell "$userInput = Read-Host;"') обрабатывается в node.js?

Я экспериментирую с приведенным ниже кодом, чтобы проверить, как child_process.exec() в node.js обрабатывает стандартный ввод от пользователя.

import { exec } from 'child_process';
exec('powershell "$userInput = Read-Host;"', (err, stdout, stderr) => {
  if (err) throw err;
  console.info(stdout);
  console.info(stderr);
});

Когда я пропустил это через node main.js, терминал работал вечно без каких-либо выходных данных.

Кажется, что функция exec() создает новую оболочку, ожидающую, пока пользователь ее введет. Однако мне не удалось найти место, где это можно было бы сделать.

Поэтому мне интересно, есть ли какие-нибудь способы показать это место или решить эту проблему без необходимости использовать Read-Host для получения пользовательского ввода.


Обновление: интересно, могу ли я перенаправить пользовательский ввод в текущий процесс (т. е. node.js) в подпроцесс (т. е. powershell), а также вывод подпроцесса в текущий процесс с помощью exec или любого другого API.

🤔 А знаете ли вы, что...
Node.js поддерживает работу с протоколами HTTP, HTTPS, TCP и UDP.


1
52
1

Ответ:

Решено

Предполагая, что вы спрашиваете, как программно предоставить входные данные stdin для запущенного дочернего процесса:

  • Используйте spawn вместо exec (последний включает в себя оболочку по умолчанию, соответствующую платформе, которая здесь не нужна).

  • Через возвращенный объект дочернего процесса используйте .stdin.write() для записи в его поток stdin; обязательно позвоните .stdin.end() после того, как все входные данные будут предоставлены, иначе дочерний процесс не завершится.

  • В коде, переданном в powershell.exe , CLI Windows PowerShell, используйте автоматическую переменную $input для доступа к вводу со стандартного ввода.

import { spawn } from 'child_process'

// Note the use of $input to refer to stdin input.
let ps = spawn(
  'powershell.exe', 
  [
    '-NoProfile', '-Command', 
    '$userInput = $input; "You entered: $userInput"'
  ]
)

// Connect the child process' output streams to the calling process'
ps.stdout.pipe(process.stdout)
ps.stderr.pipe(process.stderr)

// Write the desired input to the child process' stdin.
ps.stdin.write('user input')

// Close stdin; without this, the child process won't terminate.
ps.stdin.end()

Как вы сами обнаружили, если вы хотите соединить поток stdin вызывающего процесса с потоком stdin дочернего процесса PowerShell, то есть передать входные данные stdin, полученные текущим процессом, дочернему процессу, замените вызовы ps.stdin.write('user input') и ps.stdin.end() на:

// Relay the current process' stdin input to the PowerShell child process.
process.stdin.pipe(ps.stdin)

Примечание:

  • Если вы не предоставляете ввод со стандартного ввода в свой скрипт при вызове, он будет запрошен в интерактивном режиме (из-за автоматической переменной PowerShell $input, пытающейся прочитать из стандартного ввода, который по умолчанию используется для ввода с терминала (консоли)):

    • На Unix-подобных платформах вы можете отправлять интерактивно вводимые данные с помощью Ctrl+D.

    • В Windows вы можете использовать Ctrl+Z, а затем Enter, но в текущей LTS/стабильной версии Node.js (v20.15.0/v22.3.0), похоже, это не работает: интерактивное приглашение продолжается. (Только Ctrl+C завершает интерактивную подсказку, что, однако, прерывает обработку).