Передача в подпроцесс 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, "'\\''") + "'" }
Другие вопросы по тегам