假设我想运行命令
dmesg | rg -i hda
。我如何使用 process.spawn
或 libuv luv 中的任何其他异步函数运行它并捕获输出而不使用 sh -c "dmesg | rg -i hda"
生成 shell?
这里涉及几个步骤。首先也是最重要的,您需要两个管道。
第一个我们将调用
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
。但这些当然是可以改变的。
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 ()