#subprocess #racket
#подпроцесс #racket
Вопрос:
Как бы вы реализовали следующую процедуру в Racket:
(command->string "printf" "hello world")
таким образом, чтобы:
- Он запускает
argv[]
'("printf" "hello world")
в подпроцессе, находяprintf
вPATH
. - Если подпроцесс завершается с нулевым кодом, возвращает стандартный вывод в виде строки.
- Если подпроцесс завершается ненулевым, возникает исключение.
- Stdin и stderr игнорируются; они такие же, как для процесса Racket.
Комментарии:
1. Не забудьте опубликовать написанный вами код 😉
Ответ №1:
Вы можете использовать
(with-output-to-string
(lambda ()
(or (system* (find-executable-path "printf") "hello world")
(error 'who "command failed"))))
Если вы попробуете это в Racket REPL, это сработает, но, похоже, это сбивает с толку REPL, и следующее приглашение не отображается. Я думаю, что, возможно printf
, команда просматривает stdin, или, возможно, в XREPL есть ошибка. Обертывание приведенного выше выражения с помощью
(parameterize ((current-input-port (open-input-string ""))) _)
кажется, проблема устранена.
Комментарии:
1. Спасибо. Я получаю такое же поведение. Понятия не имею, что это вызывает.
2. Как вообще
with-output-to-string
работать с подпроцессами?(with-output-to-string (lambda () (writeln (file-stream-port? (current-output-port)) (current-error-port))))
выдает#f
.3. Я думаю
system*
, что настраивает вспомогательные потоки для перемещения данных между текущими портами Racket и портами файлового потока, созданнымиsubprocess
. Поэтомуsystem*
не имеет значения, какой порт является текущим выходным портом; он просто скопирует на него данные из порта файлового потока, созданного для подпроцесса.
Ответ №2:
(define (command->string command . args)
(let-values (((sub stdout stdin stderr)
(apply subprocess #f
(current-input-port)
(current-error-port)
(find-executable-path command)
args)))
(let ((output (port->string stdout)))
(subprocess-wait sub)
(if (eqv? 0 (subprocess-status sub))
output
(error "Command failed:" (cons command args))))))
(writeln (command->string "printf" "%s" "hello world"))
На случай, если кто-нибудь из Racket читает, пожалуйста, подумайте о добавлении чего-то подобного в стандартную библиотеку. Это просто и довольно часто требуется.
Комментарии:
1. Возможно, можно было бы создать проблему на их общедоступном Github? Это довольно открытое сообщество.
2. Это не работает из REPL, потому
subprocess
что требуется, чтобы stdin был портом файла (который, я полагаю, в более широком смысле означает «порт fd» в Unix). REPLcurrent-input-port
не является файловым портом.3. FWIW: это было объединено всего пару дней назад. github.com/racket/racket/pull/3468 . Это будет в документации для Racket 7.10 / 8.0. Хотя это также несколько простой пример.