私は相当やってみたい:LUA内はどのようにしてLUAと読み書きのパイプを構築するのですか?
foo=$(echo "$foo"|someprogram)
- つまり、私はテキストの束を含む変数を持っている、と私はフィルタを介してそれを実行したいと思います(実装しますそれが起こると、Pythonで)。
ヒント
追加されました:本当にこれを可能にするLuaの標準ライブラリでは何もありません一時ファイル
私は相当やってみたい:LUA内はどのようにしてLUAと読み書きのパイプを構築するのですか?
foo=$(echo "$foo"|someprogram)
- つまり、私はテキストの束を含む変数を持っている、と私はフィルタを介してそれを実行したいと思います(実装しますそれが起こると、Pythonで)。
ヒント
追加されました:本当にこれを可能にするLuaの標準ライブラリでは何もありません一時ファイル
なるほど、おそらくよりよい解決策:
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.." !")
を使用せずにこれを実行したいと思います。
Here is an in-depth exploration of the difficulties of doing bidirectional communication properly、及び提案された解決策:
可能な場合、ファイルへのストリーム(入力または出力)の一端をリダイレクトします。すなわち:
fp = io.popen("foo >/tmp/unique", "w") fp:write(anything) fp:close() fp = io.open("/tmp/unique") x = read("*a") fp:close()
あなたは可能サブプロセスとの双方向通信を行うためにos
とio
名前空間に機能を追加しthis extensionに興味があるかもしれません。
シェルが行うよう、フィルタにデータを渡すために(フォーク()または同様の)LUAのサブプロセスを作成するためのいくつかの方法がありますか?それはデッドロックを避けるでしょう... –
Aの一時ファイルを避ける非常に良いではない解決策...
require("io")
require("posix")
x="hello\nworld"
posix.setenv("LUA_X",x)
i=popen('echo "$LUA_X" | myfilter')
x=i.read("*a")
限り、あなたのLuaがio.popen
をサポートして、この問題は簡単です。 。あなたはその後、
local foo = ...
local cmd = ("echo $foo | someprogram"):gsub('$foo', foo)
foo = os.capture(cmd)
私はこのようなすべての時間をものを行う呼び出すことができます
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 quote_me = '[^%w%+%-%=%@%_%/]' -- complement (needn't quote)
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
これはstderrをキャプチャしません。それをキャプチャする方法はありますか? –
@Vilas、stderrとstdoutを混在させたくないのであれば、 '2>&1'をコマンドラインに追加してください。あるいは、Debianスクリプト 'annotate-output'を調べてみてください。 –
この方法には非常に注意してください。コマンドラインで 'foo'の内容全体を渡すことになり、コマンドラインの大きさを保証することはできません。また、プロセスリストに表示されるので、データも公開されます。 –
ここで私はそれがlua posix
を必要とする、問題を解決する方法です。
p = require 'posix'
local r,w = p.pipe()
local r1,w1 = p.pipe()
local cpid = p.fork()
if cpid == 0 then -- child reads from pipe
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 -- parent writes to pipe
IN = r1
OUT = w
end
myProgram
実行中に、you'lが読み込まれ、通常のIOからの書き込みと、コードのこの部分の後にあなただけの子プログラムでcomunicateしIN
とOUT
で読む/書く必要があります。
私は私の問題を解決する方法については、以下のコードを参照して、同じことをやろうとしながら、この記事につまずいと良い解決策を見つけたことはありません。この実装は、ユーザーが標準入力、標準出力、標準エラー出力にアクセスし、リターンステータスコードを取得することができます。単純なラッパーは、単純なパイプコールで呼ばれています。
require("posix")
--
-- Simple popen3() implementation
--
function popen3(path, ...)
local r1, w1 = posix.pipe()
local r2, w2 = posix.pipe()
local r3, w3 = posix.pipe()
assert((w1 ~= 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)
これはかなりいいですが、これは提示されているように動作するのですか?ファイルディスクリプタの番号は1つずつオフになります(0,1,2)。forkとexecpエラーのテストは私に逆らって見えます。 – jpc
は主に私のために書かれたように動作し、 'local posix = require( "posix")'を追加する必要がありました。 – robm
私は、ps.pipe_simple()でそれらを流すためにループの後に 'posix.close(r)'と 'posix.close(e)'を追加しなければなりませんでした。さもなければ、Linux上でこれを500回コールした後、「あまりにも多くのファイルを開く」ことがあります。 – robm
拡張は不要です(lua 5.3でテスト済み)。inout.lua
として保存
#!/usr/bin/lua
-- use always locals
local stdin = io.stdin:lines()
local stdout = io.write
for line in stdin do
stdout (line)
end
とやるchmod +x /tmp/inout.lua
20:30 $ foo=$(echo "bla"| /tmp/inout.lua)
20:30 $ echo $foo
bla
なぜ 'require'についてのエラーが出ますか? "存在しないグローバル変数 'require'" –