Передача в подпроцесс stdin для JXA
Я хотел бы запустить подпроцесс в JavaScript для автоматизации (JXA) и отправить строку в stdin этого подпроцесса, которая может включать символы новой строки, мета-оболочки и т. Д. Предыдущие подходы AppleScript для этого используемого bash <<<
оператор, конкатенация строк и quoted form of
строка. Если бы был JavaScript-эквивалент quoted form of
что я могу доверять, чтобы получить все крайние случаи, я мог бы использовать тот же подход; Я исследую методы регулярных выражений в этом направлении.
Тем не менее, я подумал, так как у нас есть доступ к unistd.h
от JXA, почему бы не попробовать просто позвонить $.pipe
, $.fork
, а также $.execlp
напрямую? $.pipe
похоже, что он должен принимать массив из 2 целых чисел в качестве параметра, но ничего из того, что я пробовал, не сработало:
ObjC.import('unistd')
$.pipe() // Error: incorrect number of arguments
$.pipe([]) // segfault
$.pipe([3,4]) // segfault
$.pipe([$(), $()]) // segfault
var a = $(), b=$()
$.pipe([a,b]) // segfault
$.pipe($([a,b])) // NSException without a terribly helpful backtrace
$.pipe($([$(3), $(4)])) // segfault
var ref = Ref('int[2]')
$.pipe(ref)
ref[0] // 4, which is close!
Какие-либо предложения?
3 ответа
Я нашел подход, который работает, используя Какао вместо stdio:
ObjC.import('Cocoa')
var stdin = $.NSPipe.pipe
var stdout = $.NSPipe.pipe
var task = $.NSTask.alloc.init
task.launchPath = "/bin/cat"
task.standardInput = stdin
task.standardOutput = stdout
task.launch
var dataIn = $("foo$HOME'|\"").dataUsingEncoding($.NSUTF8StringEncoding)
stdin.fileHandleForWriting.writeData(dataIn)
stdin.fileHandleForWriting.closeFile
var dataOut = stdout.fileHandleForReading.readDataToEndOfFile
var stringOut = $.NSString.alloc.initWithDataEncoding(dataOut, $.NSUTF8StringEncoding).js
console.log(stringOut)
Действительно любопытно, что не существует JXA-эквивалента AppleScript quoted form of
для безопасной передачи литералов скрипта командам оболочки.
Тем не менее, это довольно легко реализовать:
// JXA implementation of AppleScript's `quoted form of`
function quotedForm(s) { return "'" + s.replace(/'/g, "'\\''") + "'" }
// Example
app = Application.currentApplication();
app.includeStandardAdditions = true;
console.log(app.doShellScript('cat <<<' + quotedForm("foo$HOME'|\"")))
Кредит для quotedForm()
идет к этому комментарию.
Насколько я могу судить, эта реализация делает так же, какquoted form of
делает:
В простейшей форме, если строка не содержит встроенных одинарных кавычек, онавыводится одинарными кавычками всей строки; поскольку POSIX-подобные оболочки не выполняют никакой интерполяции для строки в одинарных кавычках, она сохраняется как есть.
Если строка содержит встроенные одинарные кавычки, она эффективно разбивается на несколько строк в одинарных кавычках, причем каждая встроенная одинарная кавычка вставляется в виде
\'
(с обратной косой чертой) - это необходимо, потому что невозможно вставить одинарные кавычки в одинарные кавычки в POSIX-совместимых оболочках.
В POSIX-совместимой оболочке это должно работать для всех строк.
В функции quotedForm, приведенной выше (ниже?), Отсутствует одна очень важная функция, она только заключает в кавычки / экранирует первую строчную апострофу, в то время как ей необходимо иметь дело с тем, сколько существует в строке.
Я изменил это на то, что, кажется, работает:
// JXA implementation of AppleScript's `quoted form of`
function quotedFormOf(s) { return "'" + s.replace(/'/g, "'\\''") + "'" }