Pipe to subprocess stdin for JXA



我想在JavaScript for Automation(JXA(中启动一个子进程,并向该子进程的stdin发送一个字符串,其中可能包括换行符,shell元等。 以前的AppleScript方法使用bash的<<<运算符,字符串连接和quoted form of字符串。 如果有一个 JavaScript 等效的 quoted form of 我可以信任它来获取所有边缘情况,我可以使用相同的方法;我正在为此研究正则表达式方法。

但是,我想既然我们可以从 JXA 访问unistd.h,为什么不尝试直接调用 $.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!

有什么建议吗?

我找到了一种有效的方法,使用 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)
奇怪的是

,似乎没有类似于AppleScript的quoted form of的JXA将脚本文本安全地传递给shell命令。

但是,实现起来相当容易:

// 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 兼容的 shell 中不可能在单引号文本中嵌入单引号。

在与 POSIX 兼容的 shell 中,这应该适用于所有字符串。

上面的 quotedForm 函数(下面?(缺少一个非常重要的功能,它只引用/转义第一个内联撇号,而它需要处理字符串中存在多少撇号。

我把它改成这个似乎有效:-

// JXA implementation of AppleScript's `quoted form of`
function quotedFormOf(s) { return "'" + s.replace(/'/g, "'\''") + "'" }

最新更新