JSA里的ffi(12)——Linux里执行脚本并获取输出

wils
wils

创作者俱乐部成员

Linux版wps的Shell方法一直有问题,不能带参数执行脚本

之前分享过,使用glibc里的system方法,可以带参数,并等待脚本执行结束,是个好办法


但system方法不能获取脚本输出

现在有了ffi,正好试一下获取输出

function zz()
{
    const {pipe, close, fork, execlp} = ffi.LoadLibrary("/usr/lib/musl/lib/libc.so", {
        pipe: { returnType: "int32", parameters: ["pointer"]},
        close: { returnType: "int32", parameters: ["int32"]},
        fork: { returnType: "int32", parameters: []},
        execlp: { returnType: "int32", parameters: ["string", "string", "string", "string", "pointer"]},
    })
    const fds = FFI.Malloc(8)
    pipe(fds)
    const rdFd = fds.Read('int32', 0)
    const wtFd = fds.Read('int32', 4)
    const pid = fork()
    if (pid === 0) {
        close(rdFd)
        execlp('bash', 'bash', '-c', `echo -n 123 > /dev/fd/${wtFd}`, null)
    }
    close(wtFd)
    console.log(FileSystem.ReadFile(`/dev/fd/${rdFd}`))
    close(rdFd)
    FFI.Free(fds)
}

这里的so文件是安装了musl,如果你使用glibc,似乎需要在lib文件夹里弄个libc.so.6的别名,因为ffi现在好像不认.6结尾的文件名,有点尴尬

写的有点糙,没有对错误的处理等,但大概意思到了:

  • pipe创建管道

  • fork创建子进程,execlp执行脚本

  • 脚本里写入管道

  • FileSystem.ReadFile读取管道


不得不说,Linux里的fork、pipe、sh真是令人愉快😁

完善一下写法,包装成一个函数,就可以方便的在Linux里执行各种脚本,获取输出的结果了

十分方便,比如yad弹个日期选择框,直接curl获取图片base64编码,直接执行py获取结果等,很多问题都简单了


后面又修改了一次

function tt()
{
    const {pipe, close, dup2, fork, execlp, _exit, waitpid} = ffi.LoadLibrary("glibc.so", {
        pipe: { returnType: "int32", parameters: ["pointer"]},
        close: { returnType: "int32", parameters: ["int32"]},
        dup2: { returnType: "int32", parameters: ["int32", "int32"]},
        fork: { returnType: "int32", parameters: []},
        execlp: { returnType: "int32", parameters: ["string", "string", "string", "string", "pointer"]},
        _exit: { returnType: "void", parameters: ["int32"]},
        waitpid: { returnType: "int32", parameters: ["int32", "pointer", "int32"]},
    })
    const Fds = ffi.Array('int32', 2)
    const fds = new Fds()
    if (pipe(fds) !== 0) throw new Error('pipe failed')
    const rdFd = fds.get(0)
    const wtFd = fds.get(1)
    const pid = fork()
    if (pid < 0) throw new Error('fork failed')
    if (pid === 0) {
        close(rdFd)
        dup2(wtFd, 1)
        close(wtFd)
        execlp('bash', 'bash', '-c', `yad --calendar`, null)
        _exit(127)
    }
    close(wtFd)
    const ret = FileSystem.ReadFile(`/dev/fd/${rdFd}`)
    close(rdFd)
    waitpid(pid, null, 0)
    console.log(ret.trim())
}
海南省
浏览 188
收藏
2
分享
2 +1
5
+1
全部评论 5
 
覃欢
覃欢

@金山办公

玩的真花
· 广东省
回复
wils
wils

创作者俱乐部成员

感谢捧场wps越来越好玩了
· 海南省
回复
 
恰同学少年
· 黑龙江省
回复
 
wils
wils

创作者俱乐部成员

再加上最近挺火的iFlow,都不用学sh脚本了,一句话它自动调用imagemagick ffmpeg curl python等命名行工具完成任务 所以wps只需要搞定表格内的数据,表格外的文件操作,一句话交给iFlow就行了,这么看Linux瞬间完爆Win
· 海南省
回复
 
wils
wils

创作者俱乐部成员

可以加一句dup2,将stdout指向wtFd,脚本里就不用重定向了,直接stdout就被读取了
· 海南省
回复