melezhik has asked for the wisdom of the Perl Monks concerning the following question:

Hi! I have been using Capture::Tiny to read from processes I launch in my scripts. It works pretty good. Good module. The only thing I need more is reading processes STDOUT "in real time" which impossible with this module as it captures all the data till the process exits and then return it. It makes user waits till long running command finishes and don't let him to see it's STDOUT in real time.

Another solution with well known construction:

open(my $fh, '-|', $system_command) or die $!;
while (my $line = <$fh>) {
    # Do stuff with each $line.
}
Does not work for me, as it for mysterious reasons _sometimes_ ( some rare cases of $system_command ) it waits forever even when $system_command finishes and return all the data as STDOUT.

Any suggestions?

PS both workaround for open(my $fh, '-|', $system_command) or suggestion new IPC related module would be fine.


Thanks.

Replies are listed 'Best First'.
Re: Capture::Tiny alternative
by haukex (Archbishop) on Mar 24, 2017 at 10:27 UTC

    See the section "Streaming Output" in my node here, in particular IPC::Run might be useful to you.

    for mysterious reasons _sometimes_ ... it waits forever even when $system_command finishes

    It might be useful to debug that, since it's possible that it's the fault of the program you're calling (suffering from buffering maybe?), and/or that the other modules will suffer from exactly the same problem.

Re: Capture::Tiny alternative
by thanos1983 (Parson) on Mar 24, 2017 at 11:42 UTC

    Hello melezhik,

    Have you tried (Capture::Tiny::Extended)?

    From the documentation:

    Capture::Tiny::Extended - Capture STDOUT and STDERR from from Perl, XS + or external programs (with some extras)

    Update: Take a look also at (Handling program output in real time), maybe it will give alternative ideas.

    Hope this helps, let us know.

    Seeking for Perl wisdom...on the process of learning...not there...yet!

      I've used Capture::Tiny, but was not aware of Capture::Tiny::Extended. After checking it out, I'm not sure that I would use it or recommend using it at this point.

      Here's what I found out when looking over both Capture::Tiny and Capture::Tiny::Extended:

      • In the Description section of Capture::Tiny:Extended, the author notes that it is a fork of Capture::Tiny to add some desired functionality. The latest version of the module was released August 4, 2011. That means that it was based on version 0.11 of Capture::Tiny (released May 19, 2001) - or an earlier version of Capture::Tiny.

      • According to the change log for Capture::Tiny, version 0.12 (released December 1, 2011) added functionality from Capture::Tiny::Extended (whose author was credited in the change log too).

      • The latest version of Capture::Tiny is version 0.46 (released February 25, 2017). Doing a quick scan through the change log, it looks like there have been some fixes applied to deal with issues with the tee functionalities.

      At this point, I would say that Capture::Tiny probably now has all of the functionality of Capture::Tiny::Extended (including the tee functionalities that the OP is interested in) and probably is implementing those functionalities better than Capture::Tiny::Extended. Of course, that's just my impression after a little bit of investigation (without doing any testing).

      Just thought that I'd share what I found in case it proves useful to others.

        Hello again melezhik ,

        Create and post some example where you will be testing your code so future visitors have a good starting point or ideas on how to implement it on their project(s).

        Keep the "force" strong :D.

        Seeking for Perl wisdom...on the process of learning...not there...yet!
Re: Capture::Tiny alternative
by glasswalk3r (Friar) on Mar 25, 2017 at 22:23 UTC

    This post is getting interesting, with several different recommendations, but I think I still can add another one...

    IPC is hard... in some platforms, unreliable. MS Windows, for example, sucks completely. Even Capture::Tiny suffers over there. IPC sucks so much over there that even with a lot of gymnastics like IPC::Open3::Callback.

    It works better on UNIX, but after some time experimenting with CPAN::Reporter::Smoker, it is interesting to see that a lot of time you see the related processes waiting for output from another programs on OpenBSD for any reason that I couldn't figure out so far. It works indeed, just doesn't use CPU as I would like :-)

    So... bottom line, if you can go around IPC, do it. Otherwise be prepared to see weird stuff now and then.

    Alceu Rodrigues de Freitas Junior
    ---------------------------------
    "You have enemies? Good. That means you've stood up for something, sometime in your life." - Sir Winston Churchill
Re: Capture::Tiny alternative
by melezhik (Monk) on Mar 24, 2017 at 17:43 UTC

    Well, I have made some investigations. Looks like sshuttle daemonizes in a bad way, here is my summary:

    +-----------------------------+---------------------------------+---------------------------------+
    | Method to read from process | does script hang when reading   | Realtime process stdout teeing  |  
    |                             | from sshuttle -D is done  ?     | ( dumping to console )          | +-----------------------------+---------------------------------+---------------------------------+
     open( "$cmd | ")              yes                                yes 
     IPC::open3                    yes                                yes
     Capture::Tiny::capture        no                                 no
     Capture::Tiny::tee            yes                                yes
     IPC::Cmd::run                 yes                                yes               
     Direct run sshsulte from      no                                 yes
     terminal
    +-----------------------------+---------------------------------+---------------------------------+
    

    Further reading probably needs to be taken around function waitpid or parent -> demonized processes interaction or something like that. But unfortunately I am not a specialist in this field. So any help would be appreciated.

      Hi melezhik,

      have you tried IPC::Cmd?
      Good luck!
        Hi Fishy. Will try it as well. Thanks.

      Is that sshuttle an interactive program or a daemon? What if you run it from command line piped: sshuttle -D | cat?

      Did you try to catch/ignore signals in your perl code? Like $SIG{'TSTP'} = 'IGNORE';

        In my case sshutle gets run as daemon (-D flag). If you run it as is from terminal it gets deamonized - you can see details at https://github.com/dagolden/Capture-Tiny/issues/52

        On "Did you try to catch/ignore signals" - good idea ... but I have not tried it yet. The overall challenge is _my_ code takes sshutle as input parameter, so I can't have any guesses on what the external program could be ( any ), I don't try to get any workarounds ( like catch/ignore signals ) either.

        BTW.

        This one hangs. Though I can see some sshutle process afterwords

        $ /usr/sbin/sshuttle -v -D -r vagrant@127.0.0.1 192.168.0.0/24 | cat
        Starting sshuttle proxy.
        Listening on ('127.0.0.1', 12300).
        c : connecting to server...
        vagrant@127.0.0.1's password:
        c : connected.
        Connected.
        ^C # need to hit CTRL+C to exit
        
        $ ps uax|grep sshu
        $ ps uax| grep sshu
        root      7414  0.0  0.2  35148 10228 ?        Ss   23:03   0:00 python /usr/lib/sshuttle/main.py python -v --firewall 12300 0 --syslog
        root      7424  0.0  0.1  35524  7732 ?        S    23:03   0:00 python /usr/lib/sshuttle/main.py python -v -D -r vagrant@127.0.0.1 192.168.0.0/24
        

        And this one does not hangs. ( Similar output at STDOUT but result for ps uax|grep sshu afterwords abit different - two more processes seen )

        $ /usr/sbin/sshuttle -v -D -r vagrant@127.0.0.1 192.168.0.0/24
        Starting sshuttle proxy.
        Listening on ('127.0.0.1', 12300).
        c : connecting to server...
        vagrant@127.0.0.1's password:
        c : connected.
        Connected.
        # exit fine
        
        $ ps uax|grep sshu
        root      6860  0.0  0.0  23712  2472 pts/1    S    22:40   0:00 logger -p daemon.notice -t sshuttle
        root      6861  0.0  0.2  35148 10284 ?        Ss   22:40   0:00 python /usr/lib/sshuttle/main.py python -v --firewall 12300 0 --syslog
        root      6862  0.0  0.0  23712  2552 pts/1    S    22:40   0:00 logger -p daemon.notice -t sshuttle
        root      6899  0.0  0.1  35524  7724 ?        S    22:40   0:00 python /usr/lib/sshuttle/main.py python -v -D -r vagrant@127.0.0.1 192.168.0.0/24
        
        

Re: Capture::Tiny alternative
by Anonymous Monk on Mar 24, 2017 at 15:35 UTC
    I refuse to use any module named "Tiny" ... the place where I come from is a small town - they think so small, they use small words. But not me, I'm smarter than that. I worked it out.