• Announcement: Lua.org now officially recommends this forum as a meeting place for the Lua community

Linux Cant capture all output from io.popen (1 Viewer)

dearikomaru

Newcomer
Joined
Apr 22, 2021
Messages
3
Reaction score
0
Location
Indonesia
Lua:
function func.execute(command)
    local f = io.popen(command .. ' 2>&1 && echo " $?"')
    local output = assert(f:read "*a")
    local tempOutput = output
    local begin, _, code = output:find " (%d+)\n$"
    if begin == nil or begin == '' then
        output = table.concat(func.strSplit('\n', tempOutput), "|.|")
    else
        output, code = output:sub(1, begin - 1), tonumber(code)
    end
    return code == 0 and true or false, code, output
end
From the code above, if I run the command "cd somewhere && cat file". Condition that occurs if the first command fails (directory not found) then the resulting output is an empty string. And if all fails, then the output that is caught is only the last command (if there are 3 commands then only the 3rd output is caught). I want if the message failed that appears caught all. For example from this command "cd somewhere && cat file" and then the output is "bash: cd: somewhere: No such file or directory\n" like that. Please help me. thank you.
 

dinsdale247

Moderator
Staff member
Community Patron
Creator of WinLua
Joined
Nov 17, 2020
Messages
91
Reaction score
32
Location
Victoria BC
Website
winlua.net
Hmmm....

I don't have your func.strSplit function, but when I remove that everything runs (more or less) like you specified?

I commented out the func.strSplit. I was also getting the sh shell output so I added `bash` to the command.

Lua:
local func = {}
function func.execute(command)
    local f = io.popen(command .. ' 2>&1 && echo " $?"')
    local output = assert(f:read "*a")
    local tempOutput = output
    local begin, _, code = output:find " (%d+)\n$"
    if begin == nil or begin == '' then
        --~ output = table.concat(func.strSplit('\n', tempOutput), "|.|")
    else
        output, code = output:sub(1, begin - 1), tonumber(code)
    end
    return code == 0 and true or false, code, output
end

print(func.execute("bash cd nowhere && cat file && echo 'who done it?'"))

With `sh`
Lua:
[email protected] /tmp [1]> lua testout.lua
sh: 1: cd: can't cd to nowhere
false    nil

With `bash`
Lua:
[email protected] /tmp> lua testout.lua
bash: cd: No such file or directory
false    nil

Thoughts?
 

dearikomaru

Newcomer
Joined
Apr 22, 2021
Messages
3
Reaction score
0
Location
Indonesia
Hmmm....

I don't have your func.strSplit function, but when I remove that everything runs (more or less) like you specified?

I commented out the func.strSplit. I was also getting the sh shell output so I added `bash` to the command.

Lua:
local func = {}
function func.execute(command)
    local f = io.popen(command .. ' 2>&1 && echo " $?"')
    local output = assert(f:read "*a")
    local tempOutput = output
    local begin, _, code = output:find " (%d+)\n$"
    if begin == nil or begin == '' then
        --~ output = table.concat(func.strSplit('\n', tempOutput), "|.|")
    else
        output, code = output:sub(1, begin - 1), tonumber(code)
    end
    return code == 0 and true or false, code, output
end

print(func.execute("bash cd nowhere && cat file && echo 'who done it?'"))

With `sh`
Lua:
[email protected] /tmp [1]> lua testout.lua
sh: 1: cd: can't cd to nowhere
false    nil

With `bash`
Lua:
[email protected] /tmp> lua testout.lua
bash: cd: No such file or directory
false    nil

Thoughts?
No, it's not like that. Can you save failed messages into a variable? if the error can be caught. the printout will be like this
Lua:
[email protected] /tmp> lua testout.lua
false    nil    bash: cd: No such file or directory
Try to run one command incorrectly, then add another command incorrectly. What should be caught in the output variable is the first error. but instead of being caught and entering the variable, it is immediately printed on the screen. When run some shell script commands if the first command error. Shouldn't run any other commands. And catch the command's failed message. I try to save the error in a variable not printed on the screen. In my case I do have to give a chain commands.​

This is what i expected:
1. failed command
command : "cd somewhere"
return : false, nil, "bash: cd: somewhere: No such file or directory"
printout :
Lua:
[email protected] /tmp> lua testout.lua
false    nil    bash: cd: somewhere: No such file or directory
2. failed command && failed command
command : "cd somewhere && cat somefile"
return : false, nil, "bash: cd: somewhere: No such file or directory"
printout :
Lua:
[email protected] /tmp> lua testout.lua
false    nil    bash: cd: somewhere: No such file or directory

3. success command && failed command
command : "cd Film/ && cat somefile"
return : false, nil, "bash: cd: somewhere: No such file or directory"
printout :
Lua:
[email protected] /tmp> lua testout.lua
false    nil    cat: somefile: No such file or directory

Thanks for answering.​
 

dinsdale247

Moderator
Staff member
Community Patron
Creator of WinLua
Joined
Nov 17, 2020
Messages
91
Reaction score
32
Location
Victoria BC
Website
winlua.net
Ah, I see now. There is a thread on stack overflow that has a solution for manipulating both stderr and stdout: Use stderr in lua io.popen to determine faulty function call

The answer is that you must use something like luaposix. There is a second answer at the bottom that proposes a wrapper around luaposix, but he incorrectly linked to his master branch. I found the file he was referring to in an older branch: mkschreder/juci. It sounds like this file is what you want?

There is also a solution by Josh Jensen in his LuaPlus system. jjensen/luaplus51-all (Josh doesn't have any tags so I have to point to master.)
 

dearikomaru

Newcomer
Joined
Apr 22, 2021
Messages
3
Reaction score
0
Location
Indonesia
Ah, I see now. There is a thread on stack overflow that has a solution for manipulating both stderr and stdout: Use stderr in lua io.popen to determine faulty function call

The answer is that you must use something like luaposix. There is a second answer at the bottom that proposes a wrapper around luaposix, but he incorrectly linked to his master branch. I found the file he was referring to in an older branch: mkschreder/juci. It sounds like this file is what you want?

There is also a solution by Josh Jensen in his LuaPlus system. jjensen/luaplus51-all (Josh doesn't have any tags so I have to point to master.)
I've tried all the suggestions you gave, but nothing appropriate.
Can you help me modify my coding above?
I just studied Lua for 1 month, and it was on the router instead of a PC / laptop. :(
 

dinsdale247

Moderator
Staff member
Community Patron
Creator of WinLua
Joined
Nov 17, 2020
Messages
91
Reaction score
32
Location
Victoria BC
Website
winlua.net
So from what I can tell you're code won't work for a number of reasons. The most fundamental is the way you've strung your commands together won't capture the output. The cd command fails long before you've asked bash to pipe stderr to sdtout. io.popen won't work for your needs. The restriction seems to be in the underlying C library popen(3):

popen(): on success, returns a pointer to an open stream that can
be used to read or write to the pipe; if the fork(2) or pipe(2)
calls fail, or if the function cannot allocate memory, NULL is
returned.


Luaposix is the most robust solution, but I understand cross compiling C for luaposix may not be desirable. (If your router supports lua, it may have luaposix already on it? I forget which distros used Lua, was it openwrt?).

As an alternative, There is a suggestion to use a temp file in a lua-l thread: Re: io.popen: reading both stdout AND stderr

Some questions:
  • Do you have to string the commands together with '&&'? Could you use a script? (Much easier to redirect one call to a script)
  • Not sure if you have a filesystem on a router in which to store the temp file?
Perhaps you could answer the above and provide more context about what you're doing there could be some ways forward? I don't think stringing commands together as you have is going to work though.

As another suggestion, the lua-l mailing list is where the creators and experts can answer your questions: Lua: mailing list (click the little 'join' link). Your use case is quiet advanced, there may be more help available on a forum for the router?

Cheers.
 
Top