Announcement

Collapse
No announcement yet.
X
  • Filter
  • Time
  • Show
Clear All
new posts

  • Is there any way to get stdout echoed in the Results window from -shell- in Windows?

    I see -ashell- on SSC but that only lets me access the log of stdout after the shell closes. Why is it displayed in Linux (and, I believe, Mac) but not Windows?

  • #2
    Suppose you had it, how would you use it? Also, what about stdin? Does linux allow you to enter input in Stata's prompt even when running other processes? Sergiy

    Comment


    • #3
      I want to call an external program, which will display results in the terminal, but have those results appear in Stata's results window for convenience. That's all, nothing else.

      Comment


      • #4
        Robert, you wrote
        only lets me access the log of stdout after the shell closes
        somehow this is important for you and I don't see what difference it makes.

        Redirect DOS output to a file with >>, then type it later. I'd estimate this as
        possible, but unless you are trying to merge-in R into Stata, it's probably not
        worth the efforts.

        Best, Sergiy

        Comment


        • #5
          I wrote this a long time ago:

          Code:
           
          program def oscmd 
                  version 7
                  tempfile file 
                  ! `0' > `file' 
                  type `"`file'"' 
          end

          Comment


          • #6
            I guess that's the failsafe way. I'm writing and reading some text files already so it probably makes little difference to speed. Thanks chaps.

            Comment


            • #7
              A little update - I cracked this (at least to my satisfaction) with a program below, which puts the command in a batch file along with a 'echo Finished!', then calls the batch file through winexec and stores the stdout in a text file. Stata periodically reads the text file to look for more lines, and displays those if it finds any. This is pretty close to real-time and certainly good enough for my purposes (knowing roughly how progress of a long task is going). You can try it as
              Code:
              windowsmonitor, command(ping 127.0.0.1 -n 20)
              Of course, it only works in Windows...

              Code:
                /*
                When Stata calls another application in Windows, it can't access the stdout/stderr streams until the 
                'command prompt' window closes, unlike Linux and (I believe) OS X. The way around this is to call your
                other application with winexec not shell (or !), then get it to write output to a file, like the one 
                called "delete-me.txt" in this program. You need to define a particular line that indicates it's finished,
                otherwise Stata won't know to stop looking. Here I just have Stata read the file every 2 seconds and 
                look for new content to display until that content is "Finished!"
                 
                It assumes your other application is only ever adding lines on the end of the text file.
                 
                Example:
                windowsmonitor, command(ping 127.0.0.1 -n 20)
                */
                 
                capture program drop windowsmonitor
                program define windowsmonitor
                syntax ,COMMAND(string asis) [ WINLOGfile(string asis) waitsecs(integer 10) ]
                 
                // default winlogfile
                if ("`winlogfile'"=="") {
                local winlogfile "delete-me.txt"
                }
                 
                // delete any existing winlogfile
                ! del `winlogfile'
                 
                // construct batch file
                file open sb using "windowsmonitor.bat", write text replace
                file write sb "`macval(command)'" _n
                file write sb "echo Finished!" _n
                file close sb
                 
                // issue command, piping output to winlogfile
                winexec "windowsmonitor.bat" > `winlogfile'
                // wait up to waitsecs seconds for winlogfile to appear
                local loopcount=0
                capture confirm file `winlogfile'
                while _rc & (`loopcount'<`waitsecs') {
                sleep 1000
                capture confirm file `winlogfile'
                local ++loopcount
                }
                 
                // start reading from winlogfile
                capture file close sout
                file open sout using `winlogfile', read text
                local linecount=0
                while("`macval(lastline)'"!="Finished!") {
                sleep 2000
                // display everything after the linecount-th line
                file seek sout 0
                file read sout line
                local newlinecount=1
                if `newlinecount'>`linecount' {
                dis as result "`macval(line)'"
                }
                while r(eof)==0 {
                file read sout line
                if r(eof)==0 {
                local ++newlinecount
                if `newlinecount'>`linecount' {
                dis as result "`macval(line)'"
                }
                local lastline="`macval(line)'"
                }
                }
                local linecount=`newlinecount'
                }
                capture file close sout
                ! del `winlogfile'
                 
                end

              Comment


              • #8
                I don't see how you prevent the concurrency access problem. Without it, I expect your program to fail if you run it long enough.

                Comment


                • #9
                  Yes, that's true... maybe -capture file open- should be attempted on every reading loop, and it proceeds only if _rc==0. I'll try that out.

                  Comment


                  • #10
                    Mata seems to allow finer control over file I/O. Here's a mata implementation of the windowsmonitor program by Robert Grant, and it will keep reading the log file without needing to pause. That is, no -sleep- is needed.

                    The temporary log file is created before winexec, remove the first -sleep-. Putting the fopen() and fclose() within the while-loop and opening the file for read-only removes the second -sleep-.

                    Here's the code:
                    Code:
                    program define win_stream
                    mata win_stream(`"`0'"')
                    end
                    
                    mata:
                    void win_stream(string scalar cmd) {
                        tf = st_tempfilename()
                        stata(sprintf("shell echo --begin-- > %s", tf))
                    
                        tf_bat = st_tempfilename() + ".bat"
                        fh_cmd = fopen(tf_bat, "rw")
                        fput(fh_cmd, sprintf("%s\necho --end--", cmd))
                        fclose(fh_cmd)
                        stata(sprintf("winexec %s >> %s 2>&1", tf_bat, tf))
                        
                        pos = 0
                        thisl = ""
                        while (thisl != "--end--") {
                            fh = fopen(tf, "r")    // "r": read-only
                            fseek(fh, pos, -1)     // go to position pos with respect to -1, i.e. beginning of the file
                            thisl = fget(fh); thisl
                            pos = ftell(fh)        // store the new position
                            fclose(fh)
                        }
                    }
                    end
                    And here's an example:
                    Code:
                    . win_stream ping 8.8.8.8 -n 10
                      --begin-- 
                      
                      C:\Program Files (x86)\Stata12>ping 8.8.8.8 -n 10 
                      
                      Pinging 8.8.8.8 with 32 bytes of data:
                      Reply from 8.8.8.8: 
                      bytes=32 time=5ms TTL=56
                      Reply from 8.8.8.8: bytes=32 time=7ms TTL=56
                      Reply from 8.8.8.8: bytes=32 time=5ms TTL=56
                      Reply from 8.8.8.8: bytes=32 time=6ms TTL=56
                      Reply from 8.8.8.8: bytes=32 time=8ms TTL=56
                      Reply from 8.8.8.8: bytes=32 time=5ms 
                      TTL=56
                      Reply from 8.8.8.8: bytes=32 time=7ms TTL=56
                      Reply from 8.8.8.8: bytes=32 
                      time=7ms TTL=56
                      Reply from 8.8.8.8: bytes=32 time=6ms TTL=56
                      Reply from 8.8.8.8: bytes=32 time=8ms 
                      TTL=56
                      
                      Ping statistics for 8.8.8.8:
                          Packets: Sent = 10, Received = 10, Lost = 0 (0% loss),
                      Approximate round trip times in milli-seconds:
                          Minimum = 5ms, Maximum = 8ms, Average = 6ms
                      
                      C:\Program Files (x86)\Stata12>echo --end-- 
                      --end--

                    Comment

                    Working...
                    X