如何使用Lua构建读写管道?

我想做这样的事情:

foo=$(echo "$foo"|someprogram)

只是用 lua 实现。也就是说,我有一个包含大量文本的变量,我想通过一个过滤器运行它(实际上实现在 Python 中)。

有什么提示吗?

补充:真的很想做到这一点,而不使用临时文件

原文链接 https://stackoverflow.com/questions/1242572

点赞
stackoverflow用户64474
stackoverflow用户64474

Lua 标准库中没有任何东西可以实现这个。

这里有一个深入探讨如何正确进行双向通信的链接,以及一个提出解决方案的例子:

如果可能,将流的一端(输入或输出)重定向到一个文件中。即:

fp = io.popen("foo >/tmp/unique", "w")
fp:write(anything)
fp:close()
fp = io.open("/tmp/unique")
x = read("*a")
fp:close()

您可能会对这个扩展感兴趣,该扩展添加了在 osio 命名空间中实现与子进程双向通信的函数。

2009-08-07 02:47:54
stackoverflow用户84932
stackoverflow用户84932

一个不太好的解决方案,避免使用临时文件...

require("io")
require("posix")

x="hello\nworld"

posix.setenv("LUA_X",x)  # 设置环境变量
i=popen('echo "$LUA_X" | myfilter')  # 打开管道并执行过滤器
x=i.read("*a")  # 读取执行过滤器后的结果
2009-08-07 03:34:07
stackoverflow用户84932
stackoverflow用户84932
Aha,可能更好的解决方案:

require('posix') require('os') require('io')

function splat_popen(data,cmd) rd,wr = posix.pipe() io.flush() child = posix.fork() if child == 0 then rd:close() wr:write(data) io.flush() os.exit(1) end wr:close()

rd2,wr2 = posix.pipe() io.flush() child2 = posix.fork() if child2 == 0 then rd2:close() posix.dup(rd,io.stdin) posix.dup(wr2,io.stdout) posix.exec(cmd) os.exit(2) end wr2:close() rd:close()

y = rd2:read(“*a”) rd2:close()

posix.wait(child2) posix.wait(child)

return y end

munged = splat_popen(“hello,world”,“/usr/games/rot13”) print(“munged:”..munged..”!”)

```

2009-08-07 05:10:06
stackoverflow用户41661
stackoverflow用户41661

只要你的 Lua 支持 io.popen,这个问题就变得很容易。解决方案与你所概述的完全相同,除了你需要一个像这样的函数而不是 $(...)

function os.capture(cmd, raw)
  local f = assert(io.popen(cmd, 'r'))
  local s = assert(f:read('*a'))
  f:close()
  if raw then return s end
  s = string.gsub(s, '^%s+', '')
  s = string.gsub(s, '%s+$', '')
  s = string.gsub(s, '[\n\r]+', ' ')
  return s
end

然后你可以调用

local foo = ...
local cmd = ("echo $foo | someprogram"):gsub('$foo', foo)
foo = os.capture(cmd)

我经常做这样的事情。这里还有一个有用的函数用于形成命令:

local quote_me = '[^%w%+%-%=%@%_%/]' -- 补集(不需要引号)
local strfind = string.find

function os.quote(s)
  if strfind(s, quote_me) or s == '' then
    return "'" .. string.gsub(s, "'", [['"'"']]) .. "'"
  else
    return s
  end
end
2009-08-07 23:06:52
stackoverflow用户882913
stackoverflow用户882913

下面是我的解决方案,它需要lua posix

          p = require 'posix'
          local r,w = p.pipe()
          local r1,w1 = p.pipe()
          local cpid = p.fork()
          if cpid == 0 then -- 子进程从管道中读取
             w:close()
             r1:close()
             p.dup(r, io.stdin)
             p.dup(w1 ,io.stdout)
             p.exec('./myProgram')
             r:close()
             w1:close()
             p._exit(0)
          else -- 父进程向管道中写入
             IN = r1
             OUT = w
          end

myProgram执行期间,您将从常规io中读取和写入,执行此代码后,您只需在INOUT上写入/读取,即可与子程序通信。

2012-12-11 20:20:04
stackoverflow用户1076777
stackoverflow用户1076777

我在尝试做同样的事情时偶然发现了这篇帖子,并没有找到一个很好的解决方案,看下面的代码以了解我如何解决我的问题。此实现允许用户访问stdin、stdout、stderr并获取返回状态代码。简单的包装器用于简单的管道调用。

require("posix")

--
-- Simple popen3() implementation
--
function popen3(path, ...)
    local r1, w1 = posix.pipe()
    local r2, w2 = posix.pipe()
    local r3, w3 = posix.pipe()

    assert((r1 ~= nil or r2 ~= nil or r3 ~= nil), "pipe() failed")

    local pid, err = posix.fork()
    assert(pid ~= nil, "fork() failed")
    if pid == 0 then
        posix.close(w1)
        posix.close(r2)
        posix.dup2(r1, posix.fileno(io.stdin))
        posix.dup2(w2, posix.fileno(io.stdout))
        posix.dup2(w3, posix.fileno(io.stderr))
        posix.close(r1)
        posix.close(w2)
        posix.close(w3)

        local ret, err = posix.execp(path, unpack({...}))
        assert(ret ~= nil, "execp() failed")

        posix._exit(1)
        return
    end

    posix.close(r1)
    posix.close(w2)
    posix.close(w3)

    return pid, w1, r2, r3
end

--
-- Pipe input into cmd + optional arguments and wait for completion
-- and then return status code, stdout and stderr from cmd.
--
function pipe_simple(input, cmd, ...)
    --
    -- Launch child process
    --
    local pid, w, r, e = popen3(cmd, unpack({...}))
    assert(pid ~= nil, "filter() unable to popen3()")

    --
    -- Write to popen3's stdin, important to close it as some (most?) proccess
    -- block until the stdin pipe is closed
    --
    posix.write(w, input)
    posix.close(w)

    local bufsize = 4096
    --
    -- Read popen3's stdout via Posix file handle
    --
    local stdout = {}
    local i = 1
    while true do
        buf = posix.read(r, bufsize)
        if buf == nil or #buf == 0 then break end
        stdout[i] = buf
        i = i + 1
    end

    --
    -- Read popen3's stderr via Posix file handle
    --
    local stderr = {}
    local i = 1
    while true do
        buf = posix.read(e, bufsize)
        if buf == nil or #buf == 0 then break end
        stderr[i] = buf
        i = i + 1
    end

    --
    -- Clean-up child (no zombies) and get return status
    --
    local wait_pid, wait_cause, wait_status = posix.wait(pid)

    return wait_status, table.concat(stdout), table.concat(stderr)
end

--
-- Example usage
--
local my_in = io.stdin:read("*all")
--local my_cmd = "wc"
--local my_args = {"-l"}
local my_cmd = "spamc"
local my_args = {} -- no arguments
local my_status, my_out, my_err = pipe_simple(my_in, my_cmd, unpack(my_args))

-- Obviously not interleaved as they would have been if printed in realtime
io.stdout:write(my_out)
io.stderr:write(my_err)

os.exit(my_status)
2013-05-13 04:58:44
stackoverflow用户2779972
stackoverflow用户2779972

基于 Lua 的标准输入输出示例

这是一个非常简单的使用 Lua 编写的示例,它可以从标准输入中读取数据,并将其写入标准输出中。不需要使用额外的扩展(已测试过支持 Lua 5.3)。

#!/usr/bin/lua
-- 使用始终使用本地变量
local stdin = io.stdin:lines()
local stdout = io.write

for line in stdin do
    stdout (line)
end

将其保存为 inout.lua 文件,并使用 chmod +x /tmp/inout.lua 命令将其设置为可执行文件。

以下是一个示例,展示如何使用它来读取标准输入并将其存储在 shell 变量中:

20:30 $ foo=$(echo "bla"|  /tmp/inout.lua)
20:30 $ echo $foo
bla
2016-07-07 18:38:04
stackoverflow用户2178363
stackoverflow用户2178363
对于一个运行着 Lua 5.1 和 luaposix 35.0-1 的系统,我从此页面的 Anthony Towns 的解决方案开始,针对此 luaposix 版本使其能够在没有任何其他加密能力的系统上调用 openssl 进行加密。我试图使代码更加明确,以便将来的 luaposix API 更改时其他人也可以处理。

local posix = require('posix');
require('os');
require('io');

local function getOutputFromProcessProvidedInput( dataForProcess, command, commandArguments )
        local MAXIMUM_BYTE_READ_COUNT = 100;
        local readFileHandle1,writeFileHandle1 = posix.pipe()
        io.flush();
        local childProcessId1 = posix.fork();
        if (childProcessId1 == 0)
        then
                posix.close( readFileHandle1 );
                posix.write( writeFileHandle1, dataForProcess );
                io.flush();
                os.exit( 1 );
        end
        posix.close( writeFileHandle1 );

        local readFileHandle2,writeFileHandle2 = posix.pipe();
        io.flush();
        local childProcessId2 = posix.fork();
        if (childProcessId2 == 0)
        then
                posix.close( readFileHandle2 );
                posix.dup2( readFileHandle1, posix.fileno( io.stdin ) );
                posix.dup2( writeFileHandle2, posix.fileno( io.stdout ) );
                posix.execp( command, commandArguments );
                os.exit( 2 );
        end
        posix.close( writeFileHandle2 );
        posix.close( readFileHandle1 );

        local dataFromProcess = posix.read( readFileHandle2, MAXIMUM_BYTE_READ_COUNT );
        posix.close( readFileHandle2 );

        posix.wait( childProcessId2 );
        posix.wait( childProcessId1 );

        return dataFromProcess;
end

-- 正在执行的命令
-- echo -n AAAAAAAAAAAAAAAA | openssl aes-128-cbc -e -nopad -a -K 30313233343536373839616263646566 -iv 1FF1ECB9000000000000000000000000
-- 期望的结果
-- 28iudIC31lHfDDxfa1/g9w==
result = openReadWritePipe("AAAAAAAAAAAAAAAA","openssl",{"aes-128-cbc", "-e", "-nopad", "-a", "-K", "30313233343536373839616263646566", "-iv",  "1FF1ECB9000000000000000000000000"});
print("Result: "..result);
2022-10-19 01:16:23