Канал для подпроцесса stdin для JXA

Я хочу запустить подпроцесс в JavaScript для автоматизации (JXA) и отправить строку на стандартный ввод этого подпроцесса, который может включать новые строки, метаданные оболочки и т. д. Предыдущие подходы AppleScript для этого использовали оператор bash <<<, конкатенацию строк и quoted form of строку. Если бы существовал JavaScript-эквивалент quoted form of, которому я мог бы доверять для получения всех пограничных случаев, я мог бы использовать тот же подход; С этой целью я изучаю методы регулярных выражений.

Однако я подумал, раз у нас есть доступ к unistd.h из JXA, почему бы не попытаться просто вызвать $.pipe, $.fork и $.execlp напрямую? $.pipe похоже, что он должен принимать массив из двух целых чисел в качестве параметра, но ничего из того, что я пробовал, не сработало:

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!

Какие-либо предложения?


person Joe Hildebrand    schedule 21.12.2014    source источник


Ответы (3)


Я нашел подход, который работает, используя Cocoa вместо 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)
person Joe Hildebrand    schedule 22.12.2014
comment
Это больше не работает в Мохаве из-за удаления NSTask.launch. Любые обходные пути? - person BallpointBen; 11.07.2018
comment
Это может сработать: task.executableURL = $.NSURL.alloc.initFileURLWithPath(/bin/cat); let er = $.NSError.alloc.initWithDomainCodeUserInfo(, 0,); let ret = task.launchAndReturnError(er); if (!ret) { console.log(ОШИБКА, er.localizedDescription.UTF8String); } - person Joe Hildebrand; 09.10.2018

Действительно любопытно, что не существует 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-совместимой оболочке это должно работать для всех строк.

person mklement0    schedule 10.10.2015

Функция quotedForm выше (ниже?) не имеет одной очень важной функции, она заключает в кавычки/экранирует только первый встроенный апостроф, в то время как ей нужно иметь дело со многими существующими в строке.

Я изменил его на это, которое, кажется, работает: -

// JXA implementation of AppleScript's `quoted form of`
function quotedFormOf(s) { return "'" + s.replace(/'/g, "'\\''") + "'" }
person UKenGB    schedule 08.02.2017
comment
Хороший вопрос - да, это то, что всегда должен был делать мой ответ, и теперь он обновлен. Что касается выше и ниже. Вы не можете полагаться на определенный порядок сообщений с течением времени, поэтому лучше просто связать с другим ответом, на который вы ссылаетесь, как я сделал в этом комментарии; в Markdown вы можете построить ссылку следующим образом [<link-text>](<link-url>) и даже использовать необработанные URL-адреса (хотя это менее красиво). - person mklement0; 02.10.2018