如何在libuv luv进程中使用shell管道而不使用sh -c

问题描述 投票:0回答:2

假设我想运行命令

dmesg | rg -i hda
。我如何使用
process.spawn
或 libuv luv 中的任何其他异步函数运行它并捕获输出而不使用
sh -c "dmesg | rg -i hda"
生成 shell?

lua libuv
2个回答
0
投票

这里涉及几个步骤。首先也是最重要的,您需要两个管道。

第一个我们将调用

pipe1
,它将用于将第一个进程的 STDOUT 连接到第二个进程的 STDIN。第二个,我们称之为
pipe2
,将用于捕获第二个进程的 STDOUT。

local pipe1 = uv.new_pipe( false )
local pipe2 = uv.new_pipe( false )

接下来我们要实际生成进程。因此,为了简单起见,让我们围绕 LUV 的生成函数创建一个包装器,以便我们可以只关注相关的函数参数。

spawn( "dmesg", { }, 0, pipe1 )
spawn( "rg", { "-i", "hda" }, pipe1, pipe2 )

第三个参数是输入句柄(或文件描述符),第二个参数是输出句柄。由于第一个进程不读取其 STDIN,因此我们只需为默认 STDIN 传递零。

现在我们要从

pipe2
开始读取,直到得到 EOF。所以这很简单:

local res = ""
uv.read_start( pipe2, function ( err, chunk )
    if not chunk then
        uv.read_stop( pipe2 )
        return
    end
    res = res .. chunk
end )

最后,为了让一切运转起来,我们需要启动 LUV 的事件循环:

uv.run( )

这是整个代码,包括生成的包装器。

local uv = require( "uv" )

local function spawn( path, args, input, output )
    local options = {
        stdio = { input, output },
        args = args,
    }
    uv.spawn( path, options, function( code, signal )
        assert( code == 0, "Failed to spawn " .. path )
        uv.close( output )
    end )
end

local function read_pipe( )
    local pipe1 = uv.new_pipe( false )
    local pipe2 = uv.new_pipe( false )

    spawn( "ls", { }, 0, pipe1 )
    spawn( "awk", { [[{ print NR ": " $0; }]] }, pipe1, pipe2 )

    local res = ""
    uv.read_start( pipe2, function ( err, chunk )
        if not chunk then
            uv.read_stop( pipe2 )
            return
        end
        res = res .. chunk
    end )

    uv.run( )
    return res
end

出于测试目的,我使用了

ls
awk
。但这些当然是可以改变的。


-1
投票

尝试

io.popen()

local handle = io.popen 'dmesg | rg -i hda'
local result = handle:read '*all'
handle:close()

print (result)

P.S.我不明白你为什么使用

rg
而不是
grep
。另外,过滤可以由 Lua 本身完成:

local handle = io.popen 'dmesg'
for line in handle:lines () do
    if line:lower ():match 'hda' then
        print (line)
    end
end
handle:close ()
© www.soinside.com 2019 - 2024. All rights reserved.